“This is the 9th day of my participation in the Gwen Challenge in November. Check out the details: The Last Gwen Challenge in 2021.”
What is ARouter
ARouter is an open source Android routing framework of Ali, which helps the Componentization transformation of Android App. It supports routing, communication and decoupling between modules, and componentization can be realized by combining routing.
ARouter access
Basic usage
1. Add dependencies
android { defaultConfig { ... javaCompileOptions { annotationProcessorOptions { arguments = [AROUTER_MODULE_NAME: Project.getname ()]}}}} dependencies { Compile 'com.alibaba:arouter- API: X.X.X 'annotationProcessor 'com.alibaba:arouter-compiler: X.X.X'... } // Old version of Gradle plugin (< 2.2), you can use apt plugin, see 'other #4' at the end of this article.Copy the code
2. Add annotations
// Add annotations to the routing support page (mandatory) // The path needs to be at least two levels, /xx/xx @Route(path = "/test/activity") public class YourActivity extend Activity { ... }Copy the code
3. Initialize the SDK
If (isDebug()) {// These two lines must be written before init, otherwise these configurations will not be valid during init arouter.openlog (); // Prints the log arouter.openDebug (); // Enable debug mode (if running in InstantRun mode, debug must be enabled! } ARouter. Init (mApplication); // As early as possible, it is recommended to initialize in ApplicationCopy the code
4. Initiate routing operations
// 1. Simple in-app jump (in 'Advanced Usage' via URL jump) ARouter.getInstance().build("/test/activity").navigation(); Arouter.getinstance ().build("/test/1").withLong("key1", 666L).withString("key3", "888") .withObject("key4", new Test("Jack", "Rose")) .navigation();Copy the code
5. Confuse the rules
-keep public class com.alibaba.android.arouter.routes.**{*; } -keep public class com.alibaba.android.arouter.facade.**{*; } -keep class * implements com.alibaba.android.arouter.facade.template.ISyringe{*; } # if byType is used, add the following rule: Protection interface - keep interface * implements com in alibaba. Android. Arouter. The facade. The template. The IProvider # if you are using a single type of injection, neither define interfaces to realize IProvider, Need to add the following rules, protect realize # - keep class * implements com in alibaba. Android. Arouter. The facade. The template. IProviderCopy the code
6. Optional: Automatic loading of gradle plugin solid routing table
apply plugin: 'com.alibaba.arouter' buildscript { repositories { mavenCentral() } dependencies { classpath "com.alibaba:arouter-register:?" }}Copy the code
7. Optional: IDE plug-in to navigate to the target class
Advanced usage
1. The url jump
Public class SchemeFilterActivity extends Activity {@override} public class SchemeFilterActivity extends Activity {@override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Uri uri = getIntent().getData(); ARouter.getInstance().build(uri).navigation(); finish(); }}Copy the code
AdnroidManifest.xml
<activity android:name=".activity.SchemeFilterActivity"> <! -- Scheme --> <intent-filter> <data android:host="m.aliyun.com" android:scheme="arouter"/> <action android:name="android.intent.action.VIEW"/> <category android:name="android.intent.category.DEFAULT"/> <category android:name="android.intent.category.BROWSABLE"/> </intent-filter> </activity>Copy the code
2. Parse the parameters
// Declare a field for each parameter and use the @autowired annotation // Parcelable data cannot be passed in the URL, @route (Path = "/test/activity") public class Test1Activity extends Activity {@autoWired public String name; @Autowired int age; @autoWired (name = "girl") Boolean boy; @autowired (name = "girl") Boolean boy; // Support parsing custom objects, using JSON to pass @autoWired TestObj obj; // withObject implements the Serializable interface class (ArrayList/HashMap) Autowired List<TestObj> List; Autowired List<TestObj> List; @Autowired Map<String, List<TestObj>> map; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ARouter.getInstance().inject(this); D ("param", name + age + boy); d("param", name + age + boy); }} // If you need to pass custom objects, create a new class (not a custom object class) and implement SerializationService with the @route annotation (for users to choose their own serialization method), for example: @Route(path = "/yourservicegroupname/json") public class JsonServiceImpl implements SerializationService { @Override public void init(Context context) { } @Override public <T> T json2Object(String text, Class<T> clazz) { return JSON.parseObject(text, clazz); } @Override public String object2Json(Object instance) { return JSON.toJSONString(instance); }}Copy the code
3. The interceptor
// A classic application is to handle login events during a jump, so there is no need to repeat the login check on the target page. Multiple interceptors execute @interceptor in order of priority (priority = 8, Public class TestInterceptor implements IInterceptor {@override public void Process (Postcard, InterceptorCallback callback) { ... callback.onContinue(postcard); // Callback. OnInterrupt (new RuntimeException(" I feel something unusual ")); } @override public void init(Context Context) {// When the interceptor is initialized, this method is called when the SDK initializes. }} will only be called onceCopy the code
4. Process the jump result
// Use the navigation method with two parameters, Arouter.getinstance ().build("/test/1").navigation(this, new NavigationCallback() { @Override public void onFound(Postcard postcard) { ... } @Override public void onLost(Postcard postcard) { ... }});Copy the code
5. Customize the global degrade policy
// Achieve survival of eservice, @Route(Path = "/ XXX/XXX ") public class DegradeServiceImpl implements eservice {@override public void onLost(Context context, Postcard postcard) { // do something. } @Override public void init(Context context) { } }Copy the code
6. Declare more information for the page
// This can be extended by the Extras attribute in the Route annotation. This attribute is an int value. In other words, a single int is 4 bytes (32 bits). 32 switches can be configured // The rest can be customized, 32 switches can be identified by byte manipulation, some properties of the target page can be marked by switches, @route (path = "/test/activity", extras = consts.xxxx) @route (path = "/test/activity", extras = consts.xxxx)Copy the code
7. Decoupling through dependency injection: Exposing services
Public Interface HelloService extends IProvider {String sayHello(String name); } / / implementing an interface @ the Route path = "/ yourservicegroupname/hello", Public implements HelloService {@override public String sayHello(String name) { return "hello, " + name; } @Override public void init(Context context) { } }Copy the code
8. Decouple through dependency injection: Discover services
public class Test { @Autowired HelloService helloService; @Autowired(name = "/yourservicegroupname/hello") HelloService helloService2; HelloService helloService3; HelloService helloService4; public Test() { ARouter.getInstance().inject(this); } public void testService() {public void testService() {// 1. SayHello ("Vergil"); HelloService. sayHello("Vergil"); helloService2.sayHello("Vergil"); // 2. Use the dependency lookup method to discover the service. ByName and byType helloService3 = arouter.getInstance ().navigation(HelloService.class); helloService4 = (HelloService) ARouter.getInstance().build("/yourservicegroupname/hello").navigation(); helloService3.sayHello("Vergil"); helloService4.sayHello("Vergil"); }}Copy the code
9. Pretreatment service
// Implement PretreatmentService interface, @route (Path = "/ XXX/XXX ") public Class PretreatmentServiceImpl implements PretreatmentService {Path = "/ XXX/XXX ") public class PretreatmentServiceImpl implements PretreatmentService { @override public Boolean onpostwrite (Context Context, Postcard) {// If the Postcard needs to be processed by itself, Override public void init(Context Context) {}}Copy the code
10. Dynamic routing information
ARouter.getInstance().addRouteGroup(new IRouteGroup() { @Override public void loadInto(Map<String, RouteMeta> atlas) { atlas.put("/dynamic/activity", // path RouteMeta.build( RouteType.ACTIVITY, / / routing information TestDynamicActivity. Class, / / target class "/ dynamic/activity", / / Path "dynamic", / / Group, try to keep is the same as the Path of the first paragraph 0, // priority = 0 // Extra)); }});Copy the code
Launches with traditional IntEnts
- Communication between modules (principle to follow)
- Support url jump build(“/test/activity”).navigation()
- Support for interceptors
The principle of exploring
ARouter.init -> _ARouter.init -> LogisticsCenter.init -> ClassUtils.getFileNameByPackageName
By package name, scan the classes declared by ARouter
/** * by specifying the package name, Class name * * @param context U know * @param packageName packageName */ public static Set<String> getFileNameByPackageName(Context context, final String packageName) throws PackageManager.NameNotFoundException, IOException, InterruptedException { final Set<String> classNames = new HashSet<>(); List<String> paths = getSourcePaths(context); final CountDownLatch parserCtl = new CountDownLatch(paths.size()); for (final String path : paths) { DefaultPoolExecutor.getInstance().execute(new Runnable() { @Override public void run() { DexFile dexfile = null; try { if (path.endsWith(EXTRACTED_SUFFIX)) { //NOT use new DexFile(path), because it will throw "permission error in /data/dalvik-cache" dexfile = DexFile.loadDex(path, path + ".tmp", 0); } else { dexfile = new DexFile(path); } Enumeration<String> dexEntries = dexfile.entries(); while (dexEntries.hasMoreElements()) { String className = dexEntries.nextElement(); if (className.startsWith(packageName)) { classNames.add(className); } } } catch (Throwable ignore) { Log.e("ARouter", "Scan map file in dex files made error.", ignore); } finally { if (null ! = dexfile) { try { dexfile.close(); } catch (Throwable ignore) { } } parserCtl.countDown(); }}}); } parserCtl.await(); Log.d(Consts.TAG, "Filter " + classNames.size() + " classes by packageName <" + packageName + ">"); return classNames; }Copy the code
Activity jumps, and startActivity is finally executed
private Object _navigation(final Postcard postcard, final int requestCode, final NavigationCallback callback) { final Context currentContext = postcard.getContext(); switch (postcard.getType()) { case ACTIVITY: // Build intent final Intent intent = new Intent(currentContext, postcard.getDestination()); intent.putExtras(postcard.getExtras()); // Set flags. int flags = postcard.getFlags(); if (0 ! = flags) { intent.setFlags(flags); } // Non activity, need FLAG_ACTIVITY_NEW_TASK if (! (currentContext instanceof Activity)) { intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); } // Set Actions String action = postcard.getAction(); if (! TextUtils.isEmpty(action)) { intent.setAction(action); } // Navigation in main looper. runInMainThread(new Runnable() { @Override public void run() { startActivity(requestCode, currentContext, intent, postcard, callback); }}); break; case PROVIDER: return postcard.getProvider(); case BOARDCAST: case CONTENT_PROVIDER: case FRAGMENT: Class<? > fragmentMeta = postcard.getDestination(); try { Object instance = fragmentMeta.getConstructor().newInstance(); if (instance instanceof Fragment) { ((Fragment) instance).setArguments(postcard.getExtras()); } else if (instance instanceof android.support.v4.app.Fragment) { ((android.support.v4.app.Fragment) instance).setArguments(postcard.getExtras()); } return instance; } catch (Exception ex) { logger.error(Consts.TAG, "Fetch fragment instance error, " + TextUtils.formatStackTrace(ex.getStackTrace())); } case METHOD: case SERVICE: default: return null; } return null; }Copy the code
\