目录
Interceptor
剩下的内容其实已经不多了,但还有一个大模块我们没有进行过分析,也就是Interceptor,我们已经知道Interceptor在什么时候被使用个,但是到底如何使用它还有待分析。
直接来看InterceptorServiceImpl文件,毫无疑问,首先运行的当然是init方法(所有IProvider的init方法都是在被实例化的时候调用的,也就是LogisticsCenter.completion方法中调用的)。
@Override public void init(final Context context) { LogisticsCenter.executor.execute(new Runnable() { @Override public void run() { if (MapUtils.isNotEmpty(Warehouse.interceptorsIndex)) { for (Map.Entry> entry : Warehouse.interceptorsIndex.entrySet()) { Class interceptorClass = entry.getValue(); try { IInterceptor iInterceptor = interceptorClass.getConstructor().newInstance(); iInterceptor.init(context); 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."); synchronized (interceptorInitLock) { interceptorInitLock.notifyAll(); } } } }); }
通过LogisticsCenter提供的一个线程池创建了一个线程,并且在该线程中运行初始化。实际上,interceptor的方法都是在线程中运行的,所有要警惕界面操作!
init方法目的很简单,将所有interceptor实例化,并且初始化,然后保存到Warehouse中。
我们在_ARouter中通过方法doInterceptions方法调用了interceptors,那么就来看看该方法到底是这么做的:
public void doInterceptions(final Postcard postcard, final InterceptorCallback callback) { if (CollectionUtils.isNotEmpty(Warehouse.interceptors)) { checkInterceptorsInitStatus(); if (!interceptorHasInit) { callback.onInterrupt(new HandlerException("Interceptors initialization takes too much time.")); return; } LogisticsCenter.executor.execute(new Runnable() { @Override public void run() { CancelableCountDownLatch interceptorCounter = new CancelableCountDownLatch(Warehouse.interceptors.size()); try { _excute(0, interceptorCounter, postcard); 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. callback.onInterrupt(new HandlerException(postcard.getTag().toString())); } else { callback.onContinue(postcard); } } catch (Exception e) { callback.onInterrupt(e); } } }); } else { callback.onContinue(postcard); } }
如果没有interceptor那么直接运行callback的oncontinue方法,注意实在主线程中运行的。
接下去的代码可能是我最无法理解的地方了:
private static void checkInterceptorsInitStatus() { synchronized (interceptorInitLock) { while (!interceptorHasInit) { try { interceptorInitLock.wait(10 * 1000); } catch (InterruptedException e) { throw new HandlerException(TAG + "Interceptor init cost too much time error! reason = [" + e.getMessage() + "]"); } } } }
该方法用来判断是否已经完成了初始化,如果没有完成,等待10秒!可问题是在线程中进行初始化,确保不阻塞主线程,但是对于初始化完成的判断竟然会在主线程中调用wait方法,这是我不能理解的地方。
继续回到上面代码,使用CountDownLatch来进行线程操作计数,对于使用它来进行计数的原因个人理解在下文有分析,但是也不知道意图是否真的就是这样。_excute方法实际调用了拦截器的真实操作:
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() { @Override public void onContinue(Postcard postcard) { // Last interceptor excute over with no exception. counter.countDown(); _excute(index + 1, counter, postcard); // When counter is down, it will be execute continue ,but index bigger than interceptors size, then U know. } @Override public void onInterrupt(Throwable exception) { // Last interceptor excute over with fatal exception. postcard.setTag(null == exception ? new HandlerException("No message.") : exception.getMessage()); // save the exception message for backup. counter.cancel(); // Be attention, maybe the thread in callback has been changed, // then the catch block(L207) will be invalid. // The worst is the thread changed to main thread, then the app will be crash, if you throw this exception!// if (!Looper.getMainLooper().equals(Looper.myLooper())) { // You shouldn't throw the exception if the thread is main thread.// throw new HandlerException(exception.getMessage());// } } }); } }
从index为0开始,遍历调用所有的interceptor的processor方法,这里大概就是CountDownLatch配合await的作用所在了,开发者自定义的Interceptor可以新启线程,或者在当前线程运行。只有当所有interceptor都回调了onContinue或者某个线程调用了onIntercept之后,调用打断器过程才会结束。
至此interceptor的内容也基本分析完全了。
init
对于init的代码分析其实真的已经没啥必要了,还是用一张流程图来说明吧:
总得来说流程很简单,实际上就是进行了两个操作,初始化LogisticsCenter加载processor生成的部分文件,另外就是实例化了InterceptorServiceImpl类,相当于初始化了interceptor的功能。
总结
摘录github上该项目的功能描述:
- 从外部URL映射到内部页面,以及参数传递与解析
- 跨模块页面跳转,模块间解耦
- 拦截跳转过程,处理登陆、埋点等逻辑
- 跨模块API调用,通过控制反转来做组件解耦
确实每一点都能够在源码中找到对应的内容,比如跨模块API调用和控制反转就是IProvider来实现的,Service继承IProvider向外提供接口,内部事先封闭。
至于具体的使用在github项目主页已经有比较清楚的表述了,结合源代码之后一切都是了然的。所以也就不再加分析了。