美文网首页
Arouter源码分析之拦截处理

Arouter源码分析之拦截处理

作者: 风月寒 | 来源:发表于2020-10-16 10:11 被阅读0次

    在初始化的时候,还有一处没有分析

    if (hasInit) {
         _ARouter.afterInit();
    }
    
    static void afterInit() {
       interceptorService = (InterceptorService) ARouter.getInstance().build("/arouter/service/interceptor").navigation();
    }
    

    在源码的解释是出发拦截器的初始化。

    LogisticsCenter.completion(postcard);
    public synchronized static void completion(Postcard postcard) {
                switch (routeMeta.getType()) {
                    // 是provider类型的目标类必须实现IProvider的接口
                    case PROVIDER:  
                        
                        //获取provider目标类的Class对象
                        Class<? extends IProvider> providerMeta = (Class<? extends IProvider>) routeMeta.getDestination();
                        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());
                            }
                        }
                        // 当是provider类型的时候,把获取到的目标类的实例设置到Postcard中,
                        postcard.setProvider(instance);
                        // 设置是绿色通道 ---> 所谓的绿色的通道就是不用去执行拦截器的逻辑
                        postcard.greenChannel();    
                        break;
                    case FRAGMENT:
                        //同样是fragment类别的 也是绿色通道的
                        postcard.greenChannel();    
                    default:
                        break;
                }
            }
        }
    

    在completion方法中,如果类型是PROVIDER,而InterceptorService是继承IProvider的接口,所以当获取provider目标类的Class对象为空的时候,会调用provider.init(mContext),provider的具体实现类是InterceptorServiceImpl,因此为调用InterceptorServiceImpl的init().

    InterceptorServiceImpl # init
     @Override
        public void init(final Context context) {
            LogisticsCenter.executor.execute(new Runnable() {
                @Override
                public void run() {
                    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();
                                iInterceptor.init(context);
                                Warehouse.interceptors.add(iInterceptor);
                            } catch (Exception ex) {
                            
                            }
                        }
    
                        interceptorHasInit = true;
                        synchronized (interceptorInitLock) {
                            interceptorInitLock.notifyAll();
                        }
                    }
                }
            });
        }
    

    主要是用反射获取到实例,而这个实例使我们自定义的拦截器的实例。

    然后将自定义的实例填充到interceptors的集合中,然后将interceptorHasInit置为true,表示拦截器初始化完毕。

    当正常我们进行页面跳转的时候,不是绿色通道需要去调用InterceptorServiceImpl中的doInterceptions()

    _Arouter # navigation
    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
                     *
                     * @param postcard route meta
                     */
                    @Override
                    public void onContinue(Postcard postcard) {
                        _navigation(context, postcard, requestCode, callback);
                    }
    
                    /**
                     * Interrupt process, pipeline will be destory when this method called.
                     *
                     * @param exception Reson of interrupt.
                     */
                    @Override
                    public void onInterrupt(Throwable exception) {
                        if (null != callback) {
                            callback.onInterrupt(postcard);
                        }
    
                        logger.info(Consts.TAG, "Navigation failed, termination by interceptor : " + exception.getMessage());
                    }
                });
    

    有上面可知,拦截器在异步线程里执行,不然太多的拦截器可能会造成ANR。

    InterceptorServiceImpl # 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() {
                        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);
            }
        }
    

    会开启一个线程池去执行拦截器中的逻辑。

    InterceptorServiceImpl # _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);
                //执行自定义拦截器的 process()方法
                iInterceptor.process(postcard, new InterceptorCallback() {
                    @Override
                    public void onContinue(Postcard postcard) {
                        counter.countDown();
                        _excute(index + 1, counter, postcard);  
                    }
    
                    @Override
                    public void onInterrupt(Throwable exception) {
                        postcard.setTag(null == exception ? new HandlerException("No message.") : exception.getMessage());    // save the exception message for backup.
                        counter.cancel();
                        }
                    }
                });
            }
        }
        
    

    依次取出拦截器实例,然后调用拦截器的process方法,传入回调接口 InterceptorCallBack

    正常的话就会走 onCointinue()方法 然后重新执行 _execute()方法只不过需要将index+1了,依次执行process的方法。

    在我们自定义的拦截器中,会设置一个优先级。

    @Interceptor(priority = 1)
    public class TestInterceptor implements IInterceptor {}
    

    注解中的 priority属性值 越小会被先执行

    。这个跟我们数据仓库中 Warehouse # interceptorIndex有关系 它是一个红黑树结构的集合是按照顺序存储的,key是以priority,value是我们自定义拦截器的Class对象

    当我们从interceptorIndex取出Class对象的时候,是按照 存储的优先级拿到的

    相关文章

      网友评论

          本文标题:Arouter源码分析之拦截处理

          本文链接:https://www.haomeiwen.com/subject/emjopktx.html