git地址:ARouter
集中式的URL管理:谈到集中式的管理,总是比较蛋疼,多人协同开发的时候,大家都去AndroidManifest.xml中定义各种IntentFilter,使用隐式Intent,最终发现AndroidManifest.xml中充斥着各种Schame,
各种Path,需要经常解决Path重叠覆盖、过多的Activity被导出,引发安全风险等问题
可配置性较差:Manifest限制于xml格式,书写麻烦,配置复杂,可以自定义的东西也较少
跳转过程中无法插手:直接通过Intent的方式跳转,跳转过程开发者无法干预,一些面向切面的事情难以实施,比方说登录、埋点这种非常通用的逻辑,在每个子页面中判断又很不合理,毕竟activity已经实例化了
跨模块无法显式依赖:在App小有规模的时候,我们会对App做水平拆分,按照业务拆分成多个子模块,之间完全解耦,通过打包流程控制App功能,这样方便应对大团队多人协作,互相逻辑不干扰,这时候只能依赖隐式Intent跳转,书写麻烦,成功与否难以控制。
Alibaba的ARoute为了解决这些问题
使用
配置
compile 'com.alibaba:arouter-api:1.2.1.1'
annotationProcessor 'com.alibaba:arouter-compiler:1.1.4'
建议在Application中注册
if (BuildConfig.DEBUG) { // 这两行必须写在init之前,否则这些配置在init过程中将无效
ARouter.openLog(); // 打印日志
ARouter.openDebug(); // 开启调试模式(如果在InstantRun模式下运行,必须开启调试模式!线上版本需要关闭,否则有安全风险)
}
ARouter.init(this); // 尽可能早,推荐在Application中初始化
页面简单跳转
ARouter.getInstance().build("/study/tab").navigation();
需要跳转的Activity配置
@Route(path = "/study/tab")
public class TabActivity extends AppCompatActivity{
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tab);
}
}
AndroidManifest.xml不需要配置schema
<activity android:name=".TabActivity" />
跳转并携带参数
ARouter.getInstance().build("/study/testargs")
.withString("key","Main")
.navigation();
去读参数
@Route(path = "/study/testargs")
public class TestArgsActivity extends AppCompatActivity{
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test_args);
String key = getIntent().getStringExtra("key");
Toast.makeText(this, key, Toast.LENGTH_SHORT).show();
}
}
拦截器可以用来登录啥的巴拉巴拉。。
@Interceptor(priority = 8)
public class TestInterceptor implements IInterceptor {
@Override
public void process(Postcard postcard, InterceptorCallback callback) {
Log.e("inter","msg");
callback.onContinue(postcard);
}
@Override
public void init(Context context) {
}
}
通过Uri跳转拦截
public class SchameFilterActivity extends AppCompatActivity{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Uri uri = getIntent().getData();
if(uri == null){
finish();
return;
}
Postcard postcard = ARouter.getInstance().build(uri);
// for (String key: uri.getQueryParameterNames()){
// postcard.withString(key, uri.getQueryParameter(key));
// }
postcard.navigation(null, new NavigationCallback() {
@Override
public void onFound(Postcard postcard) {
}
@Override
public void onLost(Postcard postcard) {
}
@Override
public void onArrival(Postcard postcard) {
}
@Override
public void onInterrupt(Postcard postcard) {
}
});
finish();
}
}
Uri跳转参数自动读取
@Route(path = "/study/testargs2")
public class TestArgs2Activity extends AppCompatActivity{
@Autowired
public String key;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test_args);
ARouter.getInstance().inject(this);
Toast.makeText(this, key, Toast.LENGTH_SHORT).show();
}
}
关于实现原理
使用Processor在编译器读取注解的Activity和注解的path,使用javapoet生成ARouter$$Group$$path 文件 里面保存页面的路由信息
/**
* DO NOT EDIT THIS FILE!!! IT WAS GENERATED BY AROUTER. */
public class ARouter$$Group$$study implements IRouteGroup {
@Override
public void loadInto(Map<String, RouteMeta> atlas) {
atlas.put("/study/tab", RouteMeta.build(RouteType.ACTIVITY, TabActivity.class, "/study/tab", "study", null, -1, -2147483648));
atlas.put("/study/testargs", RouteMeta.build(RouteType.ACTIVITY, TestArgsActivity.class, "/study/testargs", "study", null, -1, -2147483648));
atlas.put("/study/testargs2", RouteMeta.build(RouteType.ACTIVITY, TestArgs2Activity.class, "/study/testargs2", "study", new java.util.HashMap<String, Integer>(){{put("key", 8); }}, -1, -2147483648));
}
}
在页面第一次跳转的时候,将路由信息读取到Warehouse的routes,在寻找路由进行跳转。
关于编译时生成代码 请参考 编译时生成代码