ARouter的使用以及遇到的问题
app随着业务的越来越复杂,代码量越来越大,导致了各种问题亟待解决:
- 整体打包速度变慢。
- 业务间耦合较高。
为了解决上述问题,我们进行了组件化重构,本文不对组件化方案进行详细的介绍。组件化重构又要解决组件与组件之间的耦合问题—例如页面之间的跳转。所以在项目中引入了 ARouter。
本文将介绍ARouter的使用以及使用中遇到的问题。
ARouter支持的特性
-
支持url标准解析以及跳转(url绑定特定的activity页面),自动注入参数。
-
多组件支持(解耦)
-
支持跳转拦截处理—登录,统计以及其他逻辑
-
跨组件通信解耦以及依赖倒置
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 {
//查找到路由地址
。。。。。
}
}