今天本来是想做一键打包的优化 毕竟现在的那套架构已经用了好一段时间,当初为了公司业务,实现了基本功能,后来因为其它事务太多,就没再跟进这块,一直想再深入优化,实现结构上更加清晰,让其它同学可以快速应用。不知不觉 查到ARouter上来,初步觉得这东西对我有用,就深入的研究了一下。
源码地址:https://github.com/alibaba/ARouter;
一、功能介绍
支持直接解析标准URL进行跳转,并自动注入参数到目标页面中
支持多模块工程使用
支持添加多个拦截器,自定义拦截顺序
支持依赖注入,可单独作为依赖注入框架使用
支持InstantRun
支持MultiDex(Google方案)
映射关系按组分类、多级管理,按需初始化
支持用户指定全局降级与局部降级策略
页面、拦截器、服务等组件均自动注册到框架
支持多种方式配置转场动画
支持获取Fragment
完全支持Kotlin以及混编(配置见文末 其他#5)
二、典型应用
从外部URL映射到内部页面,以及参数传递与解析
跨模块页面跳转,模块间解耦
拦截跳转过程,处理登陆、埋点等逻辑
跨模块API调用,通过控制反转来做组件解耦
三、基础功能
添加依赖和配置
defaultConfig {
...
javaCompileOptions {
annotationProcessorOptions {
arguments= [moduleName:project.getName() ]
}
}
}
compile'com.alibaba:arouter-api:1.2.4'
annotationProcessor'com.alibaba:arouter-compiler:1.1.4'
添加注解
//在支持路由的页面上添加注解(必选)//这里的路径需要注意的是至少需要有两级,/xx/xx@Route(path="/test/activity")publicclassYourActivityextend Activity {...}
初始化SDK
if(isDebug()) {//这两行必须写在init之前,否则这些配置在init过程中将无效ARouter.openLog();//打印日志ARouter.openDebug();//开启调试模式(如果在InstantRun模式下运行,必须开启调试模式!线上版本需要关闭,否则有安全风险)}ARouter.init(mApplication);//尽可能早,推荐在Application中初始化
发起路由操作
//1. 应用内简单的跳转(通过URL跳转在'进阶用法'中)
ARouter.getInstance().build("/test/activity").navigation();//2. 跳转并携带参数ARouter.getInstance().build("/test/1").withLong("key1",666L).withString("key3","888").withObject("key4",newTest("Jack","Rose")).navigation();
添加混淆规则(如果使用了Proguard)
-keep public class com.alibaba.android.arouter.routes.**{*;}
-keep class * implements com.alibaba.android.arouter.facade.template.ISyringe{*;}
# 如果使用了 byType 的方式获取 Service,需添加下面规则,保护接口
-keep interface * implements com.alibaba.android.arouter.facade.template.IProvider
# 如果使用了 单类注入,即不定义接口实现 IProvider,需添加下面规则,保护实现
-keep class * implements com.alibaba.android.arouter.facade.template.IProvider
实现起来也并不麻烦
初探之下 有8种用途 我看重的是第7种 解藕 暴露服务 也着重写了这块的DEMO
1、通过URL跳转
//新建一个Activity用于监听Schame事件,之后直接把url传递给ARouter即可publicclassSchameFilterActivityextendsActivity{@OverrideprotectedvoidonCreate(BundlesavedInstanceState) {super.onCreate(savedInstanceState);Uriuri=getIntent().getData();ARouter.getInstance().build(uri).navigation();finish(); }}
AndroidManifest.xml
2、解析URL中的参数
// 为每一个参数声明一个字段,并使用 @Autowired 标注
// URL中不能传递Parcelable类型数据,通过ARouter api可以传递Parcelable对象
@Route(path ="/test/activity")
public classTest1ActivityextendsActivity {
@Autowired
publicStringname;
@Autowired
intage;
@Autowired(name ="girl")// 通过name来映射URL中的不同参数
booleanboy;
@Autowired
TestObjobj;// 支持解析自定义对象,URL中使用json传递
@Override
protected voidonCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ARouter.getInstance().inject(this);
// ARouter会自动对字段进行赋值,无需主动获取
Log.d("param",name+age+boy);
}
}
// 如果需要传递自定义对象,需要实现 SerializationService,并使用@Route注解标注(方便用户自行选择序列化方式),例如:
@Route(path ="/service/json")
public classJsonServiceImplimplementsSerializationService {
@Override
public voidinit(Context context) {
}
@Override
publicTjson2Object(String text,Class clazz) {
returnJSON.parseObject(text,clazz);
}
@Override
publicStringobject2Json(Object instance) {
returnJSON.toJSONString(instance);
}
}
3、声明拦截器(拦截跳转过程,面向切面编程)
// 比较经典的应用就是在跳转过程中处理登陆事件,这样就不需要在目标页重复做登陆检查
// 拦截器会在跳转之间执行,多个拦截器会按优先级顺序依次执行
@Interceptor(priority =8,name ="测试用拦截器")
public classTestInterceptorimplementsIInterceptor {
@Override
public voidprocess(Postcard postcard,InterceptorCallback callback) {
...
callback.onContinue(postcard);// 处理完成,交还控制权
// callback.onInterrupt(new RuntimeException("我觉得有点异常")); // 觉得有问题,中断路由流程
// 以上两种至少需要调用其中一种,否则不会继续路由
}
@Override
public voidinit(Context context) {
// 拦截器的初始化,会在sdk初始化的时候调用该方法,仅会调用一次
}
}
4、处理跳转结果
// 使用两个参数的navigation方法,可以获取单次跳转的结果
ARouter.getInstance().build("/test/1").navigation(this, newNavigationCallback() {
@Override
public voidonFound(Postcard postcard) {
...
}
@Override
public voidonLost(Postcard postcard) {
...
}
});
5、自定义全局降级策略
// 实现DegradeService接口,并加上一个Path内容任意的注解即可
@Route(path ="/xxx/xxx")
public classDegradeServiceImplimplementsDegradeService {
@Override
public voidonLost(Context context,Postcard postcard) {
// do something.
}
@Override
public voidinit(Context context) {
}
}
6、为目标页面声明更多信息
//我们经常需要在目标页面中配置一些属性,比方说"是否需要登陆"之类的//可以通过 Route 注解中的 extras 属性进行扩展,这个属性是一个 int值,换句话说,单个int有4字节,也就是32位,可以配置32个开关//剩下的可以自行发挥,通过字节操作可以标识32个开关,通过开关标记目标页面的一些属性,在拦截器中可以拿到这个标记进行业务逻辑判断
@Route(path="/test/activity",extras=Consts.XXXX)
7、通过依赖注入解耦:服务管理(一) 暴露服务
// 声明接口,其他组件通过接口来调用服务
public interfaceHelloServiceextendsIProvider {
StringsayHello(String name);
}
// 实现接口
@Route(path="/service/hello",name="测试服务")
public classHelloServiceImplimplementsHelloService {
@Override
publicStringsayHello(String name) {
return"hello, "+ name;
}
@Override
public voidinit(Context context) {
}
}
8、通过依赖注入解耦:服务管理(二) 发现服务
public classTest {
@Autowired
HelloServicehelloService;
@Autowired(name ="/service/hello")
HelloServicehelloService2;
HelloServicehelloService3;
HelloServicehelloService4;
publicTest() {
ARouter.getInstance().inject(this);
}
public voidtestService() {
// 1. (推荐)使用依赖注入的方式发现服务,通过注解标注字段,即可使用,无需主动获取
// Autowired注解中标注name之后,将会使用byName的方式注入对应的字段,不设置name属性,会默认使用byType的方式发现服务(当同一接口有多个实现的时候,必须使用byName的方式发现服务)
helloService.sayHello("Vergil");
helloService2.sayHello("Vergil");
// 2. 使用依赖查找的方式发现服务,主动去发现服务并使用,下面两种方式分别是byName和byType
helloService3= ARouter.getInstance().navigation(HelloService.class);
helloService4= (HelloService) ARouter.getInstance().build("/service/hello").navigation();
helloService3.sayHello("Vergil");
helloService4.sayHello("Vergil");
}
}
总结:最后发现 并不适合我的需求,不过 这确实是个好东西,其它场景使用 是没问题的,但对于我要实现的中间件 还缺少一些东西 需要我自己写 ,而原来写的架构与使用它相差不了多少,总结下来,最初 是没 真正区分好 什么是模块化 什么是组件化,什么又是插件化,所以走偏了路。 在此 我再做下总结:
-
模块化:项目按照独立的模块进行划分
-
组件化:将项目按照单一的组件来进行划分结构
-
模块化与组件化的差别在于颗粒度,个人认为模块相对于组件的粒度较大!组件分的更细。一个模块可以由很多个组件构成~
-
个人感觉模块化和组件化无非就是业务和基础支撑库拆分粒度的区别。
-
插件化:一个程序划分为不同的部分,以插件的形式加载到应用中去,本质上它使用的技术还是热修复技术,只是加入了更多工程实践,让它支持大规模的代码更新以及资源和SO包的更新。
组件化是编译时合并到主工程,插件化是运行时加载到主工程
网友评论