美文网首页
ARouter拦截器无法生效的解决办法

ARouter拦截器无法生效的解决办法

作者: 五道杠小学生 | 来源:发表于2019-06-25 14:34 被阅读0次

    按照官网提供demo,定义一个TestInterceptor类,实现IInterceptor接口,实现process抽象方法。按照指导教程,在跳转的过程中应该会调用该方法,从而实现跳转拦截,但实际上自己写的demo怎么都不会走该方法。最后把官方demo的TestInterceptor类直接拿过来用,依然不行。
    那就直接源码分析:
    process()方法是在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);
                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();
                    }
                });
            }
        }
    

    _excute在该类中的doInterceptions方法调用,通过调试,发现代码始终走不到最外面的if里面去,因为interceptors.size始终是0。

        @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);
                            ```
                            ```
                        } catch (Exception e) {
                            callback.onInterrupt(e);
                        }
                    }
                });
            } else {
                callback.onContinue(postcard);
            }
        }
    

    进一步查看Warehouse类,发现interceptors 是一个list,大致可以猜出来,是用来保存自定义拦截器的list,如果自定义了两个interceptor,那这个list的size应该就是2。看一下是在什么时候add的。

     static List<IInterceptor> interceptors = new ArrayList<>();
    

    只有一个地方add元素,在InterceptorServiceImpl的init方法中,debug发现是Warehouse.interceptorsIndex始终为0,没有走到add。

        @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);
                            ···
                            ···
        }
    

    那就再看看interceptorsIndex是什么。还是在Warehouse里面,可以看到interceptorsIndex 是一个以priority做key,IInterceptor对象做value的map。那就看看是什么时候put元素的

    static Map<Integer, Class<? extends IInterceptor>> interceptorsIndex = new UniqueKeyTreeMap<>("More than one interceptors use same priority [%s]");
    

    查看一下使用的地方,基本上都是被IInterceptorGroup接口中的loadInto抽象方法当做了参数,看到IInterceptorGroup和loadInto应该比较熟悉,如果看过Arouter拦截器原理分析,对这两个关键字应该不会陌生。
    我们自定义了一个拦截器类的时候,Arouter会自动生成一个类,继承自IInterceptorGroup ,实现了loadInto方法,“Test1Interceptor.class”就是我定义的拦截器类。在这里通过loadInto方法将我们的拦截器相关信息加入到map中去。

    /**
    * DO NOT EDIT THIS FILE!!! IT WAS GENERATED BY AROUTER. */
    public class ARouter$$Interceptors$$arouterdemo implements IInterceptorGroup {
    @Override
    public void loadInto(Map<Integer, Class<? extends IInterceptor>> interceptors) {
      interceptors.put(7, Test1Interceptor.class);
    }
    }
    

    继续debug,发现,这里没有被调用到,感觉莫名其妙,这个类都自动生成了,为什么还没有调用到这个方法,那就继续看这个方法是什么时候调用的。

    在LogisticsCenter类中的registerInterceptor方法调用

        private static void registerInterceptor(IInterceptorGroup interceptorGroup) {
            markRegisteredByPlugin();
            if (interceptorGroup != null) {
                interceptorGroup.loadInto(Warehouse.interceptorsIndex);
            }
        }
    

    registerInterceptor方法是在register方法里面调用

        private static void register(String className) {
            if (!TextUtils.isEmpty(className)) {
                try {
                    Class<?> clazz = Class.forName(className);
                    Object obj = clazz.getConstructor().newInstance();
                    if (obj instanceof IRouteRoot) {
                        registerRouteRoot((IRouteRoot) obj);
                    } else if (obj instanceof IProviderGroup) {
                        registerProvider((IProviderGroup) obj);
                    } else if (obj instanceof IInterceptorGroup) {
                        registerInterceptor((IInterceptorGroup) obj);
                    } else {
                        logger.info(TAG, "register failed, class name: " + className
                                + " should implements one of IRouteRoot/IProviderGroup/IInterceptorGroup.");
                    }
                } catch (Exception e) {
                    logger.error(TAG,"register class error:" + className);
                }
            }
        }
    

    应该就是这里了,在debug,发现register竟然没有被调用到,而且在代码中也找不到register被调用到的地方。真的头大。于是又去看下github上的官方指导,发现这么几句话:


    image.png

    貌似这个插件可以自动注册。加上去试一下。
    结果·····,竟然就好了。不是很明白括号后面的可选是什么意思。既然差了这个插件,拦截器就不能用了,为什么还是可选的。这个问题就这样处理了,所以下次遇到这样的问题,一定要多读文档,然后再看源码,不然效率太低了。

    相关文章

      网友评论

          本文标题:ARouter拦截器无法生效的解决办法

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