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

按照官网提供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上的官方指导,发现这么几句话:

《ARouter拦截器无法生效的解决办法》 image.png

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

    原文作者:五道杠小学生
    原文地址: https://www.jianshu.com/p/30c25e27f06b
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞