Arouter源码分析之拦截处理

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

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 providerMeta = (Class) 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> entry : Warehouse.interceptorsIndex.entrySet()) {
                        Class 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源码分析之拦截处理)