app隨著業(yè)務的越來越復雜,代碼量越來越大,導致了各種問題亟待解決:
- 整體打包速度變慢。
- 業(yè)務間耦合較高。
為了解決上述問題,我們進行了組件化重構,本文不對組件化方案進行詳細的介紹。組件化重構又要解決組件與組件之間的耦合問題—例如頁面之間的跳轉。所以在項目中引入了 ARouter。
本文將介紹ARouter的使用以及使用中遇到的問題。
ARouter支持的特性
支持url標準解析以及跳轉(url綁定特定的activity頁面),自動注入參數。
多組件支持(解耦)
支持跳轉攔截處理—登錄,統(tǒng)計以及其他邏輯
-
跨組件通信解耦以及依賴倒置
?
ARouter典型應用場景
- 不同組件之間activity的跳轉
- h5頁面跳轉到activity
- 登錄攔截處理—很多跳轉要先判斷是否登錄,如果沒有登錄跳轉到登錄頁面
ARouter的使用姿勢
-
配置
-
buid.gradle文件添加依賴和配置
android { defaultConfig { ... javaCompileOptions { annotationProcessorOptions { arguments = [AROUTER_MODULE_NAME: project.getName()] } } } } dependencies { // Replace with the latest version compile 'com.alibaba:arouter-api:?' annotationProcessor 'com.alibaba:arouter-compiler:?' ... } -
在代碼中添加注解
@Route(path = "/test/activity") public class YourActivity extend Activity { ... } -
在application中初始化
if (isDebug()) { // These two lines must be written before init, otherwise these configurations will be invalid in the init process ARouter.openLog(); // Print log ARouter.openDebug(); // Turn on debugging mode (If you are running in InstantRun mode, you must turn on debug mode! Online version needs to be closed, otherwise there is a security risk) } ARouter.init(mApplication); // As early as possible, it is recommended to initialize in the Application這里注意注釋,在debug模式下必須要在初始化之前調用
ARouter.openLog() ARouter.openDebug -
代碼調用
// 1. Simple jump within application (Jump via URL in 'Advanced usage') ARouter.getInstance().build("/test/activity").navigation(); // 2. Jump with parameters ARouter.getInstance().build("/test/1") .withLong("key1", 666L) .withString("key3", "888") .withObject("key4", new Test("Jack", "Rose")) .navigation(); -
proguard文件的配置
-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 you use the byType method to obtain Service, add the following rules to protect the interface: -keep interface * implements com.alibaba.android.arouter.facade.template.IProvider # If single-type injection is used, that is, no interface is defined to implement IProvider, the following rules need to be added to protect the implementation # -keep class * implements com.alibaba.android.arouter.facade.template.IProvider
-
-
使用場景
-
根據url跳轉
public class SchameFilterActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Uri uri = getIntent().getData(); ARouter.getInstance().build(uri).navigation(); finish(); } }<activity android:name=".activity.SchameFilterActivity"> <!-- Schame --> <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> -
解析參數
@Route(path = "/test/activity") public class Test1Activity extends Activity { @Autowired public String name; @Autowired int age; @Autowired(name = "girl") // Map different parameters in the URL by name boolean boy; @Autowired TestObj obj; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ARouter.getInstance().inject(this); // ARouter will automatically set value of fields Log.d("param", name + age + boy); }ARouter.getInstance().inject(this);這行代碼一定要在oncreate中調用。還支持自定義的參數解析,有這方面需求的可以去ARouter的github頁面 -
面向切面的攔截器
// A more classic application is to handle login events during a jump so that there is no need to repeat the login check on the target page. // Interceptors will be executed between jumps, multiple interceptors will be executed in order of priority @Interceptor(priority = 8, name = "test interceptor") public class TestInterceptor implements IInterceptor { @Override public void process(Postcard postcard, InterceptorCallback callback) { ... // No problem! hand over control to the framework callback.onContinue(postcard); // Interrupt routing process // callback.onInterrupt(new RuntimeException("Something exception")); // The above two types need to call at least one of them, otherwise it will not continue routing } @Override public void init(Context context) { // Interceptor initialization, this method will be called when sdk is initialized, it will only be called once } } -
跳轉回調
// U can get the result of a single jump ARouter.getInstance().build("/test/1").navigation(this, new NavigationCallback() { @Override public void onFound(Postcard postcard) { ... } @Override public void onLost(Postcard postcard) { ... } });
-
遇到的問題
-
ARouter.getInstance().inject(this);
我們有一個singletask啟動模式的activity,在onNewIntent方法中調用ARouter.getInstance().inject(this);得不到參數,查看ARouter在build過程中生成的代碼可以知道它是調用了activity的getIntent來獲取參數的,但是onNewIntent中的intent和在onCreate方法中的intent并不相同,所以需要在onNewIntent方法中調用setIntent方法,然后就能得到參數了。ARouter::Compiler >>> No module name, for more information, look at gradle log.
檢查項目依賴的全部module包括module依賴的module(沒有頁面的module也算),在每個module的 build.gradle中加上下面的代碼。
defaultConfig {
javaCompileOptions {
annotationProcessorOptions {
arguments = [ AROUTER_MODULE_NAME : project.getName() ]
}
}
}
- ARouter there's no route matched
不同module的一級路徑必須不同,否則會導致一個moudle中的一級路徑失效
下面是拋出異常的源代碼
public synchronized static void completion(Postcard postcard) {
if (null == postcard) {
throw new NoRouteFoundException(TAG + "No postcard!");
}
//查找RouteMeta對象,如果存在說明路由成功,如果失敗說明還沒有被加載或者這個path就是錯誤的
RouteMeta routeMeta = Warehouse.routes.get(postcard.getPath());
if (null == routeMeta) {
// 通過groupsIndex去找IRouteGroup的實現類
Class<? extends IRouteGroup> groupMeta = Warehouse.groupsIndex.get(postcard.getGroup());
if (null == groupMeta) {
throw new NoRouteFoundException(TAG + "There is no route match the path [" + postcard.getPath() + "], in group [" + postcard.getGroup() + "]");
} else {
// 通過反射獲取IRouteGroup的實現類,然后加載到內存
IRouteGroup iGroupInstance = groupMeta.getConstructor().newInstance();
iGroupInstance.loadInto(Warehouse.routes);
// 加載到內存后Warehouse.groupsIndex去掉這個group
Warehouse.groupsIndex.remove(postcard.getGroup());
}
} else {
//查找到路由地址
。。。。。
}
}