[Alibaba-ARouter]浅谈简单好用的Android页面路由框架
开发一款App,总会遇到各种各样的需求和业务,这时候选择一个简单好用的轮子,就可以事半功倍
前言
Intentintent=newIntent(mContext,XxxActivity.class);
intent.putExtra("key","value");
startActivity(intent);
Intentintent=newIntent(mContext,XxxActivity.class);
intent.putExtra("key","value");
startActivityForResult(intent,666);
上面一段代码,在Android开发中,最常见也是最常用的功能就是页面的跳转,我们经常需要面对从浏览器或者其他App跳转到自己App中页面的需求,不过就算是简简单单的页面跳转,随着时间的推移,也会遇到一些问题:
- 集中式的URL管理:谈到集中式的管理,总是比较蛋疼,多人协同开发的时候,大家都去AndroidManifest.xml中定义各种IntentFilter,使用隐式Intent,最终发现AndroidManifest.xml中充斥着各种Schame,各种Path,需要经常解决Path重叠覆盖、过多的Activity被导出,引发安全风险等问题
- 可配置性较差:Manifest限制于xml格式,书写麻烦,配置复杂,可以自定义的东西也较少
- 跳转过程中无法插手:直接通过Intent的方式跳转,跳转过程开发者无法干预,一些面向切面的事情难以实施,比方说登录、埋点这种非常通用的逻辑,在每个子页面中判断又很不合理,毕竟activity已经实例化了
- 跨模块无法显式依赖:在App小有规模的时候,我们会对App做水平拆分,按照业务拆分成多个子模块,之间完全解耦,通过打包流程控制App功能,这样方便应对大团队多人协作,互相逻辑不干扰,这时候只能依赖隐式Intent跳转,书写麻烦,成功与否难以控制。
另一个轮子
为了解决以上问题,我们需要一款能够解耦、简单、功能多、定制性较强、支持拦截逻辑的路由组件:我们选择了Alibaba的ARouter。
一、功能介绍
- 支持直接解析URL进行跳转、参数按类型解析到Bundle,支持Java基本类型(*)
- 支持应用内的标准页面跳转,API接近Android原生接口
- 支持多模块工程中使用,允许分别打包,包结构符合Android包规范即可(*)
- 支持跳转过程中插入自定义拦截逻辑,自定义拦截顺序(*)
- 支持服务托管,通过ByName,ByType两种方式获取服务实例,方便面向接口开发与跨模块调用解耦(*)
- 映射关系按组分类、多级管理,按需初始化,减少内存占用提高查询效率(*)
- 支持用户指定全局降级策略
- 支持获取单次跳转结果
- 丰富的API和可定制性
- 被ARouter管理的页面、拦截器、服务均无需主动注册到ARouter,被动发现
- 支持AndroidN推出的Jack编译链
二、不支持的功能
- 自定义URL解析规则(考虑支持)
- 不能动态加载代码模块和添加路由规则(考虑支持)
- 多路径支持(不想支持,貌似是导致各种混乱的起因)
- 生成映射关系文档(考虑支持)
三、典型应用场景
- 从外部URL映射到内部页面,以及参数传递与解析
- 跨模块页面跳转,模块间解耦
- 拦截跳转过程,处理登陆、埋点等逻辑
- 跨模块API调用,模块间解耦(注册ARouter服务的形式,通过接口互相调用)
四、基础功能
添加依赖和配置
applyplugin:'com.neenbedankt.android-apt'
buildscript{
repositories{
jcenter()
}
dependencies{
classpath'com.neenbedankt.gradle.plugins:android-apt:1.4'
}
}
apt{
arguments{
moduleNameproject.getName();
}
}
dependencies{
apt'com.alibaba:arouter-compiler:x.x.x'
compile'com.alibaba:arouter-api:x.x.x'
...
}
添加注解
//在支持路由的页面、服务上添加注解(必选)
//这是最小化配置,后面有详细配置
@Route(path="/test/1")
publicclassYourActivityextendActivity{
...
}
初始化SDK
ARouter.init(mApplication);//尽可能早,推荐在Application中初始化
发起路由操作
//1.应用内简单的跳转(通过URL跳转在'中阶使用'中)
ARouter.getInstance().build("/test/1").navigation();
//2.跳转并携带参数
ARouter.getInstance().build("/test/1")
.withLong("key1",666L)
.withString("key3","888")
.navigation();
添加混淆规则(如果使用了Proguard)
-keeppublicclasscom.alibaba.android.arouter.routes.**{*;}
五、进阶用法
通过URL跳转
//新建一个Activity用于监听Schame事件
//监听到Schame事件之后直接传递给ARouter即可
//也可以做一些自定义玩法,比方说改改URL之类的
//http://www.example.com/test/1
publicclassSchameFilterActivityextendsActivity{
@Override
protectedvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
//外面用户点击的URL
Uriuri=getIntent().getData();
//直接传递给ARouter即可
ARouter.getInstance().build(uri).navigation();
finish();
}
}
//AndroidManifest.xml中的参考配置
使用ARouter协助解析参数类型
//URL中的参数会默认以String的形式保存在Bundle中
//如果希望ARouter协助解析参数(按照不同类型保存进Bundle中)
//只需要在需要解析的参数上添加@Param注解
@Route(path="/test/1")
publicclassTest1ActivityextendsActivity{
@Param//声明之后,ARouter会从URL中解析对应名字的参数,并按照类型存入Bundle
publicStringname;
@Param
privateintage;
@Param(name="girl")//可以通过name来映射URL中的不同参数
privatebooleanboy;
@Override
protectedvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
name=getIntent().getStringExtra("name");
age=getIntent().getIntExtra("age",-1);
boy=getIntent().getBooleanExtra("girl",false);//注意:使用映射之后,要从Girl中获取,而不是boy
}
}
开启ARouter参数自动注入(实验性功能,不建议使用,正在开发保护策略)
//首先在Application中重写attachBaseContext方法,并加入ARouter.attachBaseContext();
@Override
protectedvoidattachBaseContext(Contextbase){
super.attachBaseContext(base);
ARouter.attachBaseContext();
}
//设置ARouter的时候,开启自动注入
ARouter.enableAutoInject();
//至此,Activity中的属性,将会由ARouter自动注入,无需getIntent().getStringExtra("xxx")等等
声明拦截器(拦截跳转过程,面向切面搞事情)
//比较经典的应用就是在跳转过程中处理登陆事件,这样就不需要在目标页重复做登陆检查
//拦截器会在跳转之间执行,多个拦截器会按优先级顺序依次执行
@Interceptor(priority=666,name="测试用拦截器")
publicclassTestInterceptorimplementsIInterceptor{
/**
*Theoperationofthisinterceptor.
*
*@parampostcardmeta
*@paramcallbackcb
*/
@Override
publicvoidprocess(Postcardpostcard,InterceptorCallbackcallback){
...
callback.onContinue(postcard);//处理完成,交还控制权
//callback.onInterrupt(newRuntimeException("我觉得有点异常"));//觉得有问题,中断路由流程
//以上两种至少需要调用其中一种,否则会超时跳过
}
/**
*Doyourinitworkinthismethod,itwellbecallwhenprocessorhasbeenload.
*
*@paramcontextctx
*/
@Override
publicvoidinit(Contextcontext){
}
}
处理跳转结果
//通过两个参数的navigation方法,可以获取单次跳转的结果
ARouter.getInstance().build("/test/1").navigation(this,newNavigationCallback(){
@Override
publicvoidonFound(Postcardpostcard){
...
}
@Override
publicvoidonLost(Postcardpostcard){
...
}
});
自定义全局降级策略
//实现DegradeService接口,并加上一个Path内容任意的注解即可
@Route(path="/xxx/xxx")//必须标明注解
publicclassDegradeServiceImplimplementsDegradeService{
/**
*Routerhaslost.
*
*@parampostcardmeta
*/
@Override
publicvoidonLost(Contextcontext,Postcardpostcard){
//dosomething.
}
/**
*Doyourinitworkinthismethod,itwellbecallwhenprocessorhasbeenload.
*
*@paramcontextctx
*/
@Override
publicvoidinit(Contextcontext){
}
}
为目标页面声明更多信息
//我们经常需要在目标页面中配置一些属性,比方说"是否需要登陆"之类的 //可以通过Route注解中的extras属性进行扩展,这个属性是一个int值,换句话说,单个int有4字节,也就是32位,可以配置32个开关 //剩下的可以自行发挥,通过字节操作可以标识32个开关 @Route(path="/test/1",extras=Consts.XXXX)
使用ARouter管理服务(一)暴露服务
/**
*声明接口
*/
publicinterfaceIServiceextendsIProvider{
Stringhello(Stringname);
}
/**
*实现接口
*/
@Route(path="/service/1",name="测试服务")
publicclassServiceImplimplementsIService{
@Override
publicStringhello(Stringname){
return"hello,"+name;
}
/**
*Doyourinitworkinthismethod,itwellbecallwhenprocessorhasbeenload.
*
*@paramcontextctx
*/
@Override
publicvoidinit(Contextcontext){
}
}
使用ARouter管理服务(二)发现服务
1.可以通过两种API来获取Service,分别是ByName、ByType
IServiceservice=ARouter.getInstance().navigation(IService.class);//ByType
IServiceservice=(IService)ARouter.getInstance().build("/service/1").navigation();//ByName
service.hello("zz");
2.注意:推荐使用ByName方式获取Service,ByType这种方式写起来比较方便,但如果存在多实现的情况时,SDK不保证能获取到你想要的实现
使用ARouter管理服务(三)管理依赖
可以通过ARouterservice包装您的业务逻辑或者sdk,在service的init方法中初始化您的sdk,不同的sdk使用ARouter的service进行调用,每一个service在第一次使用的时候会被初始化,即调用init方法。
这样就可以告别各种乱七八糟的依赖关系的梳理,只要能调用到这个service,那么这个service中所包含的sdk等就已经被初始化过了,完全不需要关心各个sdk的初始化顺序。
六、更多功能
初始化中的其他设置
ARouter.openLog();//开启日志 ARouter.printStackTrace();//打印日志的时候打印线程堆栈
详细的API说明
//构建标准的路由请求
ARouter.getInstance().build("/home/main").navigation();
//构建标准的路由请求,并指定分组
ARouter.getInstance().build("/home/main","ap").navigation();
//构建标准的路由请求,通过Uri直接解析
Uriuri;
ARouter.getInstance().build(uri).navigation();
//构建标准的路由请求,startActivityForResult
//navigation的第一个参数必须是Activity,第二个参数则是RequestCode
ARouter.getInstance().build("/home/main","ap").navigation(this,5);
//直接传递Bundle
Bundleparams=newBundle();
ARouter.getInstance()
.build("/home/main")
.with(params)
.navigation();
//指定Flag
ARouter.getInstance()
.build("/home/main")
.withFlags();
.navigation();
//觉得接口不够多,可以直接拿出Bundle赋值
ARouter.getInstance()
.build("/home/main")
.getExtra();
//使用绿色通道(跳过所有的拦截器)
ARouter.getInstance().build("/home/main").greenChannal().navigation();
附录
ARouterGithub链接
最新版本
- arouter-annotation:1.0.0
- arouter-compiler:1.0.1
- arouter-api:1.0.2
Gradle依赖
dependencies{
apt'com.alibaba:arouter-compiler:1.0.1'
compile'com.alibaba:arouter-api:1.0.2'
}
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。