博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
ARouter 源码历险记 (四)
阅读量:6229 次
发布时间:2019-06-21

本文共 6223 字,大约阅读时间需要 20 分钟。

hot3.png

目录

 

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上该项目的功能描述:

  1. 从外部URL映射到内部页面,以及参数传递与解析
  2. 跨模块页面跳转,模块间解耦
  3. 拦截跳转过程,处理登陆、埋点等逻辑
  4. 跨模块API调用,通过控制反转来做组件解耦

    确实每一点都能够在源码中找到对应的内容,比如跨模块API调用和控制反转就是IProvider来实现的,Service继承IProvider向外提供接口,内部事先封闭。

    至于具体的使用在github项目主页已经有比较清楚的表述了,结合源代码之后一切都是了然的。所以也就不再加分析了。

转载于:https://my.oschina.net/zzxzzg/blog/865657

你可能感兴趣的文章
AP_应付模组在月结的处理
查看>>
javascript如何判断访问网页的设备及是否支持触屏功能
查看>>
MFC 虚函数与消息映射区别
查看>>
每日一小练——列出全部子集
查看>>
[再寄小读者之数学篇](2014-06-23 Bernstein's inequality)
查看>>
微信公众平台开发(98) UnionID
查看>>
《CLR via C#》读书笔记 之 线程基础
查看>>
Linux中的lo回环接口详细介绍
查看>>
玩转Web之servlet(三)---一张图看懂B/S架构
查看>>
Neutron中的Service类
查看>>
MCU开发之I2C通信
查看>>
angular学习笔记(二十七)-$http(5)-使用$http构建RESTful架构
查看>>
阿里集团2015届校园招聘内推
查看>>
Android 面试精华题目总结
查看>>
SQL函数简述
查看>>
Swift 注释
查看>>
应对Memcached缓存失效,导致高并发查询DB的几种思路
查看>>
PLSQL_性能优化系列14_Oracle High Water Level高水位分析
查看>>
A Game with Colored Balls
查看>>
使用哈希加盐法来为密码加密【转】
查看>>