首页 > 编程知识 正文

arouter源码分析,arouter源码

时间:2023-05-03 18:00:06 阅读:227985 作者:1369

内推

【长期有效】欢迎加入字节跳动我的团队:内推链接

ARouter,A framework for assisting in the renovation of Android componentization (帮助 Android App 进行组件化改造的路由框架) —— 支持模块间的路由、通信、解耦

官方中文介绍:
https://github.com/alibaba/ARouter/blob/master/README_CN.md
(中文比英文文档,详尽得多…,良心文档啊)

基本使用 1.添加依赖 android { defaultConfig { javaCompileOptions { annotationProcessorOptions { //注解处理器需要的模块名,作为路径映射的前缀 arguments = [AROUTER_MODULE_NAME: project.getName()] } } }}dependencies {implementation 'com.alibaba:arouter-api:1.4.1' annotationProcessor 'com.alibaba:arouter-compiler:1.2.2' //注解处理器,会将注解编译成Java类} 2.添加注解 //注意:路劲至少两级,即xx/xx,前一个xx用于分组@Route(path = "/test/second")public class SecondActivity extends AppCompatActivity {} 3.初始化SDK

一般在Application中初始化

ARouter.init(this); 4.使用 //很简单,一句话完成,可携带参数ARouter.getInstance().build("/test/second").navigation(); 原理浅析

从ARouter.getInstance().build("/test/second").navigation();出发,解释其跳转基本过程。
先上一张时序图:

1.ARouter.build(path)构建Postcard

ARouter只是对外统一的api接口,实现基本由_ARouter完成,所以构建Postcard也是由_ARouter,构建,build(path, extractGroup(path))中extractGroup方法,就是把/xx/xx中前面的xx转换为默认group的方法,这也是之前必须使用2级以上目录的原因。build到此就完成了,此时还没有完成映射到activity的任务,只是把path浅析了下。

2.Postcard.navigation()实现跳转

最后也是由_ARouter完成,在_ARouter.navigation时,首先调用LogisticsCenter.completion(postcard)完善postcard的信息,而completion方法,则完成了path到activity的转换关系。完善后,再调用_navigation完成最终跳转。

3.LogisticsCenter.completion(postcard)将path映射到activity

核心部分:

public synchronized static void completion(Postcard postcard) {RouteMeta routeMeta = Warehouse.routes.get(postcard.getPath()); if (null == routeMeta) { Class<? extends IRouteGroup> groupMeta = Warehouse.groupsIndex.get(postcard.getGroup()); if (null == groupMeta) { throw new NoRouteFoundException(); } else { // Load route and cache it into memory, then delete from metas. try { IRouteGroup iGroupInstance = groupMeta.getConstructor().newInstance(); iGroupInstance.loadInto(Warehouse.routes); Warehouse.groupsIndex.remove(postcard.getGroup()); } catch (Exception e) { throw new HandlerException(); } completion(postcard); // Reload } } else { postcard.setDestination(routeMeta.getDestination()); //destination就是需要跳转的Activity.class ...... }}

首先去Warehouse的routes中寻找RouteMeta(路由元数据)。
Warehouse可以理解为存储路由元数据的容器,包括:路由关系、拦截器、provider的映射关系等。RouteMeta既持有activity等对应跳转类信息。
首次navigation时,RouteMeta == null,故会用postcard build时的group path先找到对一个的IRouteGroup信息[IRouteGroup何时加载到Warehouse的,见下条],然后通过iGroupInstance.loadInto将改分组下的RouteMeta都加载到缓存中,这可以理解为延迟加载,降低初始化时的一些压力。加载后,再重新调用completion(postcard)。

4.IRouteGroup的加载

路由元数据RouteMeta是从实现了IRouteGroup接口的实例中load进来的,这个实现了IRouteGroup接口的类在哪?何时load进Warehouse?在LogisticsCenter.init()方法中,找到了踪迹。

public synchronized static void init(Context context, ThreadPoolExecutor tpe) throws HandlerException { Set<String> routerMap; // It will rebuild router map every times when debuggable. if (ARouter.debuggable() || PackageUtils.isNewVersion(context)) { // These class was generated by arouter-compiler. routerMap = ClassUtils.getFileNameByPackageName(mContext, ROUTE_ROOT_PAKCAGE); if (!routerMap.isEmpty()) { context.getSharedPreferences(AROUTER_SP_CACHE_KEY, Context.MODE_PRIVATE).edit().putStringSet(AROUTER_SP_KEY_MAP, routerMap).apply(); } PackageUtils.updateVersion(context); // Save new version name when router map update finishes. } else { routerMap = new HashSet<>(context.getSharedPreferences(AROUTER_SP_CACHE_KEY, Context.MODE_PRIVATE).getStringSet(AROUTER_SP_KEY_MAP, new HashSet<String>())); } for (String className : routerMap) { if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_ROOT)) { // This one of root elements, load root. ((IRouteRoot) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.groupsIndex); } ...... } }

首次init时,通过ClassUtils.getFileNameByPackageName(mContext, ROUTE_ROOT_PAKCAGE)将ROUTE_ROOT_PAKCAGE = "com.alibaba.android.arouter.routes"下的所有类,都加载进routerMap中。然后通过区分routerMap类名,实例化com.alibaba.android.arouter.routes.ARouter##Root开头的类[由于csdn对$的支持并不友好,故以下$都使用#代替],调用其loadInto将对应的IRouteGroup类都加载到Warehouse.groupsIndex中。
PS:
init方法有一些小细节,针对debug版本或者新版本,才会有一次完整的类find和load的过程,加载完后会将类路径都存入sp,之后启动从sp拿,以增加启动速度。
ClassUtils.getFileNameByPackageName方法并不简单,其中牵扯了在多dex或者特殊rom下加载类的一些处理,有兴趣的同学可以阅读源码了解。

ARouter##Root##app

public class ARouter$$Root$$app implements IRouteRoot { public ARouter$$Root$$app() { } public void loadInto(Map<String, Class<? extends IRouteGroup>> routes) { routes.put("test", test.class); }}

ARouter##Group##test

public class ARouter$$Group$$test implements IRouteGroup { public ARouter$$Group$$test() { } public void loadInto(Map<String, RouteMeta> atlas) { atlas.put("/test/second", RouteMeta.build(RouteType.ACTIVITY, SecondActivity.class, "/test/second", "test", (Map)null, -1, -2147483648)); }} 5.Route类的生成

接着上一步的解析,下面要了解的是,ARouter##Root##app,ARouter##Group##test这些编译好的类,是何时/如何生成的。这里使用的是android的apt(Annotation Processing Tool)技术,即在编译时,将注解生成为Java代码。所以在build.gradle添加依赖时,会添加注解处理器 annotationProcessor ‘com.alibaba:arouter-compiler:1.2.2’ ,具体的处理过程,可以参见arouter-compiler的RouteProcessor,RouteProcessor代码较长,这里就不详述了。感兴趣的童鞋,可以自己写一写注解处理器,com.squareup.javapoet神器了解一下。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。