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();
}
}
android:host="m.aliyun.com"
android:scheme="arouter"/>
解析参数
@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 {
//查找到路由地址
。。。。。
}
}