Arouter
Arouter是一款路由框架,在做组件化是用于组件间通信(包括页面跳转,调用另一个组件的服务等),没分析代码认为Arouter只能用来做页面跳转,代码分析之后发现还有ICO,根据URL查找Class的功能,服务提供等。下面就开始分析Arouter
//初始化代码
public static void init(Application application) {
if (!hasInit) {
logger = _ARouter.logger;
_ARouter.logger.info(Consts.TAG, "ARouter init start.");
//进行_Arouter.init()
hasInit = _ARouter.init(application);
if (hasInit) {
_ARouter.afterInit();
}
_ARouter.logger.info(Consts.TAG, "ARouter init over.");
}
}
真正进行初始化的是_Arouter类,而Arouter是对_Arouter的功能进行封装,并且Arouter决定需要暴露哪些_Arouter的服务提供给使用者使用
- 调用_ARouter.init()进行初始化,真正进行初始化的类是_Arouter
- 调用_ARouter.afterInit()进行初始化之后的操作
下面继续追踪
protected static synchronized boolean init(Application application) {
mContext = application;
//进行LogisticsCenter的init
LogisticsCenter.init(mContext, executor);
logger.info(Consts.TAG, "ARouter init success!");
hasInit = true;
mHandler = new Handler(Looper.getMainLooper());
return true;
}
LogisticsCenter是包含了所有的map的映射,当第一次使用时创建实例,用于处理映射关系,复杂的逻辑去解决重复的组定义,简单来说就是会对处理所有使用@Route注解的类,在处理跳转等操作时会添加完善PostCard,下面详细分析下LogiscCenter
LogiscCenter
LogiscCenter有几个重要的方法,我们先看看init()方法
public synchronized static void init(Context context, ThreadPoolExecutor tpe) throws HandlerException {
//如果是debug或者是新版本,就重新加载映射关系,否则从本地获取
if (ARouter.debuggable() || PackageUtils.isNewVersion(context)) {
//加载路由映射,通过指定包名,扫描包下面包含的所有的ClassName,这里的类全是通过APT编译时生成的,这些类包含了所有的映射关系,有Route注解和IProvider服务提供者等注解
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); // 更新版本
} else {
//非debug模式,也不是新版本,就从本地获取映射关系
routerMap = new HashSet<>(context.getSharedPreferences(AROUTER_SP_CACHE_KEY, Context.MODE_PRIVATE).getStringSet(AROUTER_SP_KEY_MAP, new HashSet<String>()));
}
startInit = System.currentTimeMillis();
//遍历所有在com.alibaba.android.arouter.routes包下的类,并且做分类,分别放入Warehouse的映射对象内
for (String className : routerMap) {
if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_ROOT)) {
// 这里是根映射,对应的类为ARouter$$Root$$XXX,生成的所有group类的映射,是对分组的映射
((IRouteRoot) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.groupsIndex);
} else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_INTERCEPTORS)) {
// 加载拦截器interceptor映射
((IInterceptorGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.interceptorsIndex);
} else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_PROVIDERS)) {
// 加载服务提供者Iprovider映射
((IProviderGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.providersIndex);
}
}
...
}
- 扫描com.alibaba.android.arouter.routes包下所有的Class
- 遍历扫描到的Class的集合,如果Class是以"com.alibaba.android.arouter.routes.ARouter$$Root"开头,则这个类里面的映射装载进Warehouse.groupsIndex。这个类里面是生成的各个组映射的Class
- 如果Class是以"com.alibaba.android.arouter.routes.ARouter$$Interceptors",则装载进Warehouse.interceptorsIndex拦截器索引映射
- 如果Class是以"com.alibaba.android.arouter.routes.ARouter$$Providers",则装载进Warehouse.providersIndex服务提供者索引映射
到这一步已经把所有的@Route注解和相应的Class装载进了WareHouse里面,完成了路由映射的装载
下面再看下LogiscCenter的completion()方法,这个方法主要是对路由信息的封装类Postcard的完善,再跳转过程中,通过调用completion()方法,通过RouteMeta完善路由信息
public synchronized static void completion(Postcard postcard) {
if (null == postcard) {
throw new NoRouteFoundException(TAG + "No postcard!");
}
//首先查找路由信息是否已经加载到Warehouse.routes映射里面
RouteMeta routeMeta = Warehouse.routes.get(postcard.getPath());
if (null == routeMeta) { // 如果为null,那么可能为空,也可能是还没把对应的路由装载进来,Arouter是分组装载,在初始化是只会加载包含分组映射类Class的信息,然后根据分组再加载分组内详细的路由信息
Class<? extends IRouteGroup> groupMeta = Warehouse.groupsIndex.get(postcard.getGroup()); // 得到包含分组路由信息的类Class的
if (null == groupMeta) {
//如果没有对应分组类,则抛出异常
throw new NoRouteFoundException(TAG + "There is no route match the path [" + postcard.getPath() + "], in group [" + postcard.getGroup() + "]");
} else {
// Load route and cache it into memory, then delete from metas.
try {
if (ARouter.debuggable()) {
logger.debug(TAG, String.format(Locale.getDefault(), "The group [%s] starts loading, trigger by [%s]", postcard.getGroup(), postcard.getPath()));
}
IRouteGroup iGroupInstance = groupMeta.getConstructor().newInstance();
//把包含分组路由信息的映射装载进Warehouse.routes
iGroupInstance.loadInto(Warehouse.routes);
//移除分组group信息
Warehouse.groupsIndex.remove(postcard.getGroup());
if (ARouter.debuggable()) {
logger.debug(TAG, String.format(Locale.getDefault(), "The group [%s] has already been loaded, trigger by [%s]", postcard.getGroup(), postcard.getPath()));
}
} catch (Exception e) {
throw new HandlerException(TAG + "Fatal exception when loading group meta. [" + e.getMessage() + "]");
}
completion(postcard); // 重新继续完善
}
} else {
//把RouteMeta的相关属性设置给PostCard对象
postcard.setDestination(routeMeta.getDestination());
postcard.setType(routeMeta.getType());
postcard.setPriority(routeMeta.getPriority());
postcard.setExtra(routeMeta.getExtra());
Uri rawUri = postcard.getUri();
if (null != rawUri) { // 把Uri携带的参数信息解析出来,放进Bundle对象
Map<String, String> resultMap = TextUtils.splitQueryParameters(rawUri);
Map<String, Integer> paramsType = routeMeta.getParamsType();
if (MapUtils.isNotEmpty(paramsType)) {
// Set value by its type, just for params which annotation by @Param
for (Map.Entry<String, Integer> params : paramsType.entrySet()) {
setValue(postcard,
params.getValue(),
params.getKey(),
resultMap.get(params.getKey()));
}
// Save params name which need auto inject.
postcard.getExtras().putStringArray(ARouter.AUTO_INJECT, paramsType.keySet().toArray(new String[]{}));
}
// Save raw uri
postcard.withString(ARouter.RAW_URI, rawUri.toString());
}
switch (routeMeta.getType()) {
case PROVIDER: // 如果@Route的注解类型是服务提供者IProvider
// 获取想要获取当前IProvider的Class类型
Class<? extends IProvider> providerMeta = (Class<? extends IProvider>) routeMeta.getDestination();
//获取当前类型的实例,如果没有实例的则进行初始化,构造出IProvider
IProvider instance = Warehouse.providers.get(providerMeta);
if (null == instance) { // There's no instance of this provider
IProvider provider;
try {
provider = providerMeta.getConstructor().newInstance();
provider.init(mContext);
Warehouse.providers.put(providerMeta, provider);
instance = provider;
} catch (Exception e) {
throw new HandlerException("Init provider failed! " + e.getMessage());
}
}
postcard.setProvider(instance);//把instance设置给postcard
postcard.greenChannel(); //provider默认走绿色通道,不用经过拦截器
break;
case FRAGMENT:
postcard.greenChannel(); // Fragment类型也不需要经过拦截器
default:
break;
}
}
}
completion()做的主要工作就是找到路由类的RouteMeta对象,来完善Postcard信息
- 根据path信息在Warehouse.routes里面查找是否含有相应的RouteMeta信息
- 如果没有RouteMeta信息,那么可能是对应的分组路由的映射还没加载进内存,所以就继续查找包含分组信息映射的类,实例化对应的IRouteGroup类,把这个分组的映射关系全部加载进来,然后把Warehouse.groupsIndex移除响应分组类,装载完成后再次调用completion(),完善postcard信息
- 如果已经有RouteMeta信息,那么就把对应的RouteMeta的信息设置给postcard,如果uri携带了参数信息,就把参数信息全部装进bundle
- 如果获取的类型为PROVIDER或者FRAGMENT,那么就会开启绿色通道,不再走拦截器服务。
- 如果PROVIDER类型,对于Provider的理解是服务提供者,主要用于一个组件来向另一个组件提供服务,所以一个Class类型的的服务只有一个实例。首先会从Warehouse.providers里面获取对应的实例,如果没有,那么就初始化,然后放入Warehouse.providers映射里面。最终给postcard设置provider
下面再看下_ARouter.afterInit();方法
static void afterInit() {
// 根据Arouter用法,根据path找实例,拿到InterceptorService
interceptorService = (InterceptorService) ARouter.getInstance().build("/arouter/service/interceptor").navigation();
}
afterInit()主要是在装载完所有的路由映射后执行的操作,获取拦截器服务InterceptorService
而InterceptorService是一个IProvier,获取拦截器服务InterceptorService的过程用的还是Arouter的方式,下面再看下Arouter获取IProvider的方式,上面的方法最终会调用到_Arouter的navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback)方法
protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
...
try {
LogisticsCenter.completion(postcard);
} catch (NoRouteFoundException ex) {
logger.warning(Consts.TAG, ex.getMessage());
if (debuggable()) {
// Show friendly tips for user.
runInMainThread(new Runnable() {
@Override
public void run() {
Toast.makeText(mContext, "There's no route matched!\n" +
" Path = [" + postcard.getPath() + "]\n" +
" Group = [" + postcard.getGroup() + "]", Toast.LENGTH_LONG).show();
}
});
}
if (null != callback) {
//回调onLost()
callback.onLost(postcard);
} else {
//如果没有回调Callback,就会调用查找是否有降级服务,如果有则执行降级
DegradeService degradeService = ARouter.getInstance().navigation(DegradeService.class);
if (null != degradeService) {
degradeService.onLost(context, postcard);
}
}
return null;
}
if (null != callback) {
// 回调onFound()
callback.onFound(postcard);
}
//非绿色通道
if (!postcard.isGreenChannel()) { // It must be run in async thread, maybe interceptor cost too mush time made ANR.
//拦截器服务开始,拦截器的调用是在一步线程中,主要是防止在拦截器中执行耗时操作
interceptorService.doInterceptions(postcard, new InterceptorCallback() {
/**
* Continue process
*/
@Override
public void onContinue(Postcard postcard) {
_navigation(context, postcard, requestCode, callback);
}
/**
* Interrupt process, pipeline will be destory when this method called.
*/
@Override
public void onInterrupt(Throwable exception) {
if (null != callback) {
callback.onInterrupt(postcard);
}
logger.info(Consts.TAG, "Navigation failed, termination by interceptor : " + exception.getMessage());
}
});
} else {
//绿色通道
return _navigation(context, postcard, requestCode, callback);
}
return null;
}
- 调用LogisticsCenter.completion(postcard)把PostCard的相关属性信息全部完善
- 非绿色通道,调用拦截器服务interceptorService,如果拦截器全部通过的话,就执行_navigation(),如果拦截器执行拦截,会回调callback.onInterrupt()
- 绿色通道,直接调用_navigation()方法
因为completion()已经在上面介绍过了,拦截器服务的相关方法,放在下面再分析,继续追踪_navigation(),也是路由跳转的最后一步了
private Object _navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
//如果传入的context为null,那么就会用Application
final Context currentContext = null == context ? mContext : context;
switch (postcard.getType()) {
//如果是activity的路由类型
case ACTIVITY:
// 构建Intent
final Intent intent = new Intent(currentContext, postcard.getDestination());
//把bundle设置进intent
intent.putExtras(postcard.getExtras());
// Set flags.
int flags = postcard.getFlags();
if (-1 != flags) {
intent.setFlags(flags);
} else if (!(currentContext instanceof Activity)) { // Non activity, need less one flag.
//如果传入的context不是activity,那么启动Activity就会传入Intent.FLAG_ACTIVITY_NEW_TASK创建一个新的栈
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
// Set Actions
String action = postcard.getAction();
if (!TextUtils.isEmpty(action)) {
intent.setAction(action);
}
// 之前说过了拦截器的执行是异步的,这里就切回主线程做startActivity
runInMainThread(new Runnable() {
@Override
public void run() {
startActivity(requestCode, currentContext, intent, postcard, callback);
}
});
break;
case PROVIDER:
//如果路由类型为Provider,就直接返回IProcier对象
return postcard.getProvider();
case BOARDCAST:
case CONTENT_PROVIDER:
case FRAGMENT:
//如果是BOARDCAST,CONTENT_PROVIDER,FRAGMENT类型
Class fragmentMeta = postcard.getDestination();
try {
//实例化对象
Object instance = fragmentMeta.getConstructor().newInstance();
//如果是Fragment的话,设置传递过来的参数
if (instance instanceof Fragment) {
((Fragment) instance).setArguments(postcard.getExtras());
} else if (instance instanceof android.support.v4.app.Fragment) {
((android.support.v4.app.Fragment) instance).setArguments(postcard.getExtras());
}
return instance;
} catch (Exception ex) {
logger.error(Consts.TAG, "Fetch fragment instance error, " + TextUtils.formatStackTrace(ex.getStackTrace()));
}
case METHOD:
case SERVICE:
default:
return null;
}
return null;
}
- 先查看是否context是否为null,如果为null,则赋值为application
- 如果是activity类型,就会构造出intent,把相应的参数等信息全部带上。如果context不是activity会给intent设置Intent.FLAG_ACTIVITY_NEW_TASK,创建新的任务栈。因为拦截器的服务是在一步线程做的,所以最后的startActivity会切回主线程
- 如果是IProvider类型,那么就直接返回相应Iprovider
- 如果是Fragment类型。会实例化,然后把相关参数设置给fragment,最终返回相应实例
好了,通过上面的分析,已经把路由的跳转流程分析了一遍。具体的路由信息的装载,编译期对注解的处理等还没说。下面再把拦截器的部分分析一下
Interceptor
Arouter中的拦截器是全局,通过拦截器服务启动,下面看下拦截器服务InterceptorServiceImpl
先看下类继承结构InterceptorServiceImpl implements InterceptorService
而InterceptorService extends IProvider,所以InterceptorServiceImpl就是一个IProvider。并且IInterceptor extends IProvider,所以拦截器IInterceptor也是单例,即服务提供者
private static boolean interceptorHasInit;//服务是否初始化完成
private static final Object interceptorInitLock = new Object();//拦截器初始化锁,保证服务在初始化完成后启动
接着看一下init()方法,由于InterceptorServiceImpl是IProvider,所以会在第一次初始化的时候就会调用init()方法
@Override
public void init(final Context context) {
//调用线程池异步执行任务
LogisticsCenter.executor.execute(new Runnable() {
@Override
public void run() {
//判断拦截器索引Warehouse.interceptorsIndex是否为空,即是否有拦截器
if (MapUtils.isNotEmpty(Warehouse.interceptorsIndex)) {
for (Map.Entry<Integer, Class<? extends IInterceptor>> entry : Warehouse.interceptorsIndex.entrySet()) {
Class<? extends IInterceptor> interceptorClass = entry.getValue();
try {
//初始化拦截器
IInterceptor iInterceptor = interceptorClass.getConstructor().newInstance();
//调用拦截器的init方法
iInterceptor.init(context);
//把初始化好的拦截器添加进拦截器列表Warehouse.interceptors中
Warehouse.interceptors.add(iInterceptor);
} catch (Exception ex) {
throw new HandlerException(TAG + "ARouter init interceptor error! name = [" + interceptorClass.getName() + "], reason = [" + ex.getMessage() + "]");
}
}
//拦截器初始化标志完成
interceptorHasInit = true;
logger.info(TAG, "ARouter interceptors init over.");
//把等待获取interceptorInitLock锁的线程唤醒
synchronized (interceptorInitLock) {
interceptorInitLock.notifyAll();
}
}
}
});
}
- 异步执行初始化任务,首先判断拦截索引Warehouse.interceptorsIndex是否为空,即是否有拦截器
- 遍历拦截器索引列表,实例化每个拦截器,并调用拦截器的init()方法,然后把初始化好的IInterceptor添加进拦截器列表Warehouse.interceptors
- 把interceptorHasInit置为true,唤醒正在等待获取interceptorInitLock锁的线程
Warehouse.interceptorsIndex里面的数据是在LogisticsCenter的init()方法里面被赋值的
下面再看看拦截器服务里面的doInterceptions()方法
@Override
public void doInterceptions(final Postcard postcard, final InterceptorCallback callback) {
//如果有拦截器的话
if (null != Warehouse.interceptors && Warehouse.interceptors.size() > 0) {
//检查拦截器的初始化状态
checkInterceptorsInitStatus();
if (!interceptorHasInit) {
callback.onInterrupt(new HandlerException("Interceptors initialization takes too much time."));
return;
}
LogisticsCenter.executor.execute(new Runnable() {
@Override
public void run() {
//可取消的CountDownLatch,countDown的值为拦截器的数量
CancelableCountDownLatch interceptorCounter = new CancelableCountDownLatch(Warehouse.interceptors.size());
try {
//开始执行第一个拦截器的拦截,这个方法会一直调用拦截器列表中下一个拦截器的拦截
_excute(0, interceptorCounter, postcard);
//interceptorCounter等待,如果超时300s还没有执行完,这个方法也会返回
interceptorCounter.await(postcard.getTimeout(), TimeUnit.SECONDS);
//如果拦截列表中的拦截方法还没执行完,就执行拦截
if (interceptorCounter.getCount() > 0) { // Cancel the navigation this time, if it hasn't return anythings.
callback.onInterrupt(new HandlerException("The interceptor processing timed out."));
} else if (null != postcard.getTag()) { // Maybe some exception in the tag.
//如果tag有值,tag是用来携带拦截过程中抛出的异常
callback.onInterrupt(new HandlerException(postcard.getTag().toString()));
} else {
//如果上面的情况都没有,那就是正常的返回,所有的拦截方法都执行完了,就继续执行,回调onContinue
callback.onContinue(postcard);
}
} catch (Exception e) {
callback.onInterrupt(e);
}
}
});
} else {
//没有拦截器的话,就继续执行,回调onContinue
callback.onContinue(postcard);
}
}
- 首先阻塞等待拦截器服务是否初始化完成
- 初始化完成后,创建CancelableCountDownLatch,countDown的值为拦截器的列表,调用_excute(0, interceptorCounter, postcard);开始执行每一个拦截器的拦截方法。
- 如果interceptorCounter.await()返回了,如果interceptorCounter的值还没归0,就代表是超时返回,那么就执行拦截回调,调用callback.onInterrupt()。
- 如果interceptorCounter不是超时返回,就代表是正常返回,那么就判断postcard的tag是否有值,如果在拦截过程中需要拦截,那么就需要给tag赋值。所以tag不为null的话,就表示出了异常,需要拦截,执行回调callback.onInterrupt()
- 如果tag为null,那么就是正常情况,执行回调callback.onContinue()
下面在继续分析_excute()方法,分析下拦截器如何一个个往下传的
//index :在拦截器列表中的索引值
//CancelableCountDownLatch : 传进来的CountDownLatch,用于在拦截时,快速清零返回
// postcard : postcard对象,发生拦截时会给postcard的tag字段赋值
private static void _excute(final int index, final CancelableCountDownLatch counter, final Postcard postcard) {
if (index < Warehouse.interceptors.size()) {
IInterceptor iInterceptor = Warehouse.interceptors.get(index);
iInterceptor.process(postcard, new InterceptorCallback() {
//如果上一个拦截器执行完了,那么允许接着执行下一个拦截的话,就回调onContinue方法
@Override
public void onContinue(Postcard postcard) {
//上一个拦截器顺利通过,counter调用countDown把值减一
counter.countDown();
// 执行下一个拦截器,索引值加1
_excute(index + 1, counter, postcard);
}
//如果不允许执行下一个拦截器的话,就回调onInterrupt()方法,进行打断拦截
@Override
public void onInterrupt(Throwable exception) {
//上一个拦截器发生了拦截,给postcard的tag赋值
postcard.setTag(null == exception ? new HandlerException("No message.") : exception.getMessage()); // save the exception message for backup.
//对counter清零,是其立刻返回
counter.cancel();
}
});
}
}
- 获取对应索引值的拦截器,执行process()方法,并且传入回调InterceptorCallback
- 如果拦截器顺利执行,回调onCotinue(),counter减一,继续执行下一个拦截器
- 如果拦截器拦截,回调onInterrupt(),给postcard的tag赋值,counter清零,立刻返回结束counter的等待
拦截器服务的内容页分析完了
网友评论