Android 使用阿里ARouter页面跳转浅析


在工作的项目中使用到了阿里的开源工具Arouter作为页面跳转路由,这里记录一下自己对于该框架使用一次跳转的研究。

首先附上github链接GitHub - alibaba/ARouter: An android router middleware that help app navigating to activities and custom services.,对于Arouter的适用性、优点和用法可以自行了解。

在项目中加入了Arouter跳转的代码后,运行项目,首先你会发现一些清单文件,位置在/build/generated/source/apt/release/com/alibaba/android/arouter/routes/下:

Android 使用阿里ARouter页面跳转浅析_第1张图片


这里的几个类分别实现了不同的接口,IRouteGroup、IInterceptorGroup、IProviderGroup、IRouteRoot,这里我们以页面的跳转分析为主,点开IRouteRoot、IRouteGroup的实现类,你会发现它们都在loadInto方法对传入的容器填充了一些数据,在IRouteRoot的实现类中传了IRouteGroup实现类的类名,在IRouteGroup实现类中传入了一个封装的RouteMeta的对象:


Android 使用阿里ARouter页面跳转浅析_第2张图片

仔细一看每个RouteMeta的参数是不是很熟悉?里面出现了你已配置路径的页面名以及注解@Route中设置的path值:


Android 使用阿里ARouter页面跳转浅析_第3张图片

其实在开发者配置完成后,ARouter会生成这些清单文件,在调用初始化方法init时会去加载这些清单文件,将配置的页面缓存起来,同时你也已经发现在loadinfo方法中体现的调用关系是存在root、group这些概念的。

如果你已经了解过Arouter,一定知道Arouter的一个特点:

映射关系按组分类、多级管理,按需初始化

在这里按组分类、多级管理其实已经体现出来了。

看完了清单文件,我们从Arouter的初始化开始入手:

ARouter.init(application);

往下查看,我们发现其实是调用了

_ARouter.init(application)

最终加载清单文件是LogisticsCenter.init方法中实现,关键代码如下:


Android 使用阿里ARouter页面跳转浅析_第4张图片

首先我们按照正常的rlease版本的流程,进入else的代码块,这里发现routerMap是从数据库里面拿出来的,接来下对routerMap的内容className做循环判断,这里className的三个判断条件其实分别是:


ROUTE_ROOT_PAKCAGE +DOT +SDK_NAME +SEPARATOR +SUFFIX_ROOT:


com.alibaba.android.arouter.routes.ARouter$$Root


ROUTE_ROOT_PAKCAGE +DOT +SDK_NAME +SEPARATOR +SUFFIX_INTERCEPTORS:


com.alibaba.android.arouter.routes.ARouter$$Interceptors


ROUTE_ROOT_PAKCAGE+DOT +SDK_NAME +SEPARATOR +SUFFIX_PROVIDERS:


com.alibaba.android.arouter.routes.ARouter$$Providers


找到了清单文件类之后传入了Warehouse类中的成员变量并表用loadInfo方法,到此初始化已经结束,再进入Warehouse中瞧一瞧:


Android 使用阿里ARouter页面跳转浅析_第5张图片

可见对于页面来说,清单的配置最后被缓存到了WareHouse这个类,页面只缓存到了节点不做下级的加载,这也就是之前说的按需加载,这里只存到了类名并没有把节点全部缓存下来。

在发起一个页面跳转的请求的时,所有的请求都被封装成了一个Postcard对象,我们先来看看这个对象如何生成的,最开始Arouter调用的是build方法:


_Arouter的build方法返回了一个新的Postcar对象:


Android 使用阿里ARouter页面跳转浅析_第6张图片

看看这个PathReplaceService是如何生成的,顺着navigation方法往下看,最后在_Arouter的navigation的方法中返回

Android 使用阿里ARouter页面跳转浅析_第7张图片

这里在buildProvider中会对IRouterProvider的缓存中查询是否注册了对应的provider,仅仅只做页面跳转这里可以不用注册,那么整个方法会抛出异常,在catch块中返回null。那么在build中则会进入build(path, extractGroup(path))方法:


Android 使用阿里ARouter页面跳转浅析_第8张图片

在这个方法中,由上面的分析可知这里的pService为空,所以最简单的情况就是返回一个新的由path和group决定的Postcard。

再进行跳转时,将会调用Postcard的navigation方法,最终是将自己传入了_Arouter的navigation方法中:

protected Object navigation(final Context context,final Postcard postcard,final int requestCode,final NavigationCallback callback) 

在该方法中首先调用了LogisticsCenter.completion(postcard),这方法比较长,一段一段来看,其实这是个注册Postcard的方法:


Android 使用阿里ARouter页面跳转浅析_第9张图片

首先从Root容器中去查找有没有对应的内容,从我们之前的加载过程中看是肯定找不到的,那么第二步则从Group中去找,找到了之后则把页面的内容加载到routes容器中,这里是通过之前init缓存的类名找到对应的Group,然后调用Group的loadInfo方法缓存具体的每个节点,也就是到了要使用的时候再加载具体的节点,loadInfo是最开始清单文件中IRouterGroup实现类的方法,具体的填充过程看一下就知道了,再重新reload。



Android 使用阿里ARouter页面跳转浅析_第10张图片

else代码块里对于已经缓存的内容,则把相应的属性填入Postcard中,也就是把routeMeta转化为Postcard

Android 使用阿里ARouter页面跳转浅析_第11张图片

在最后会对routeMeta的类型做判断,在清单文件类中,new reoutMeta时会将页面的类型传入,所以这里是可以判断的。

在LogisticsCenter.completion(postcard)完成之后接着判断是否走的是绿色通道greenChanel(跳过所有的拦截器):


Android 使用阿里ARouter页面跳转浅析_第12张图片

我们先看跳过拦截器的else内的代码块,接着调用_navigation()方法:


Android 使用阿里ARouter页面跳转浅析_第13张图片

可见跳转的地方就在这里啦,在回到之前是否走绿色通道的逻辑,如果是不跳过拦截器,则会调用interceptorService.doInterceptions(postcard,new InterceptorCallback()),这里interceptorService是一个接口,我们找到它的实现类com.alibaba.android.arouter.core.InterceptorServiceImpl瞧一瞧doInterceptions()方法:


Android 使用阿里ARouter页面跳转浅析_第14张图片

着这个方法中首先会判断是否注册了拦截器被缓存进来,拦截器的缓存也是在init的操作中已经做过的,如果有的话则开启一个线程,这里拦截器相关都是异步的,因为拦截器的操作可能非常耗时,其中_excute()方法是拦截器操作的地方,接着看下去:


Android 使用阿里ARouter页面跳转浅析_第15张图片

根据index依次取出拦截器,并调用process()方法,而当我们定义一个拦截器的时候,最重要的便是重写IInterceptor的process()方法,那么到这里拦截器是如何运作已经一目了然了:

Android 使用阿里ARouter页面跳转浅析_第16张图片

还有一个问题,拦截器是有优先级的,这里又是怎么按照优先级拦截,如果断开后续拦截又是怎么断开的,首先我们看在代码中定义的拦截器,这里使用了注解去定义该拦截器的优先级:


在清单文件中加载拦截器时会将该优先级作为key填充到容器中:

Android 使用阿里ARouter页面跳转浅析_第17张图片

在_excute()方法中从缓存中调用拦截器是从index=0作为索引开始的,如果继续拦截则在continue中使index+1并递归,这样就实现了按照优先级拦截:


Android 使用阿里ARouter页面跳转浅析_第18张图片

在清单文件中拦截器的加载说明Warehouse中interceptorsIndex存储的内容以拦截器的优先级作为key,拦截器的类名作为value,并且interceptorsIndex是一个TreeMap,而拦截器具体的类在使用的时候是从interceptors中加载过来的,这其实是在InterceptorServiceImpl中完成的,在_Arouter完成init之后马上会调用一次afterInit():

interceptorService = (InterceptorService) ARouter.getInstance().build("/arouter/service/interceptor").navigation();

到最后会走到LogisticsCenter.completion()方法,在之前我们发现这个方法最后会对routMeta的类型做判断:


Android 使用阿里ARouter页面跳转浅析_第19张图片

当判断为IProvider接口类型时会调用init的方法,回到InterceptorServiceImpl你会发现这个类实现了InterceptorService接口,而InterceptorService又继承自IProvider接口,那么很明显了,看看InterceptorServiceImpl的init()方法:


Android 使用阿里ARouter页面跳转浅析_第20张图片

Warehouse.interceptors的填充就在这里了。

你可能感兴趣的:(Android 使用阿里ARouter页面跳转浅析)