Arouter

2019-12-10  本文已影响0人  嗯哼嗯哼嗯哼嗯哼

Arouter

Arouter是一款路由框架,在做组件化是用于组件间通信(包括页面跳转,调用另一个组件的服务等),没分析代码认为Arouter只能用来做页面跳转,代码分析之后发现还有ICO,根据URL查找Class的功能,服务提供等。下面就开始分析Arouter

//初始化代码
public static void init(Application application) {
    if (!hasInit) {
        logger = _ARouter.logger;
        _ARouter.logger.info(Consts.TAG, "ARouter init start.");
        //进行_Arouter.init()
        hasInit = _ARouter.init(application);

        if (hasInit) {
            _ARouter.afterInit();
        }

        _ARouter.logger.info(Consts.TAG, "ARouter init over.");
    }
}

真正进行初始化的是_Arouter类,而Arouter是对_Arouter的功能进行封装,并且Arouter决定需要暴露哪些_Arouter的服务提供给使用者使用

  1. 调用_ARouter.init()进行初始化,真正进行初始化的类是_Arouter
  2. 调用_ARouter.afterInit()进行初始化之后的操作

下面继续追踪

protected static synchronized boolean init(Application application) {
    mContext = application;
    //进行LogisticsCenter的init
    LogisticsCenter.init(mContext, executor);
    logger.info(Consts.TAG, "ARouter init success!");
    hasInit = true;
    mHandler = new Handler(Looper.getMainLooper());

    return true;
}

LogisticsCenter是包含了所有的map的映射,当第一次使用时创建实例,用于处理映射关系,复杂的逻辑去解决重复的组定义,简单来说就是会对处理所有使用@Route注解的类,在处理跳转等操作时会添加完善PostCard,下面详细分析下LogiscCenter

LogiscCenter

LogiscCenter有几个重要的方法,我们先看看init()方法

public synchronized static void init(Context context, ThreadPoolExecutor tpe) throws HandlerException {
    

        //如果是debug或者是新版本,就重新加载映射关系,否则从本地获取
        if (ARouter.debuggable() || PackageUtils.isNewVersion(context)) {
            //加载路由映射,通过指定包名,扫描包下面包含的所有的ClassName,这里的类全是通过APT编译时生成的,这些类包含了所有的映射关系,有Route注解和IProvider服务提供者等注解
            routerMap = ClassUtils.getFileNameByPackageName(mContext, ROUTE_ROOT_PAKCAGE);
            if (!routerMap.isEmpty()) {
                context.getSharedPreferences(AROUTER_SP_CACHE_KEY, Context.MODE_PRIVATE).edit().putStringSet(AROUTER_SP_KEY_MAP, routerMap).apply();
            }

            PackageUtils.updateVersion(context);    // 更新版本
        } else {
            //非debug模式,也不是新版本,就从本地获取映射关系
            routerMap = new HashSet<>(context.getSharedPreferences(AROUTER_SP_CACHE_KEY, Context.MODE_PRIVATE).getStringSet(AROUTER_SP_KEY_MAP, new HashSet<String>()));
        }

        
        startInit = System.currentTimeMillis();
        //遍历所有在com.alibaba.android.arouter.routes包下的类,并且做分类,分别放入Warehouse的映射对象内
        for (String className : routerMap) {
            if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_ROOT)) {
                // 这里是根映射,对应的类为ARouter$$Root$$XXX,生成的所有group类的映射,是对分组的映射
                ((IRouteRoot) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.groupsIndex);
            } else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_INTERCEPTORS)) {
                // 加载拦截器interceptor映射
                ((IInterceptorGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.interceptorsIndex);
            } else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_PROVIDERS)) {
                // 加载服务提供者Iprovider映射
                ((IProviderGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.providersIndex);
            }
        }
        
      ...
}
  1. 扫描com.alibaba.android.arouter.routes包下所有的Class
  2. 遍历扫描到的Class的集合,如果Class是以"com.alibaba.android.arouter.routes.ARouter$$Root"开头,则这个类里面的映射装载进Warehouse.groupsIndex。这个类里面是生成的各个组映射的Class
  3. 如果Class是以"com.alibaba.android.arouter.routes.ARouter$$Interceptors",则装载进Warehouse.interceptorsIndex拦截器索引映射
  4. 如果Class是以"com.alibaba.android.arouter.routes.ARouter$$Providers",则装载进Warehouse.providersIndex服务提供者索引映射

到这一步已经把所有的@Route注解和相应的Class装载进了WareHouse里面,完成了路由映射的装载

下面再看下LogiscCenter的completion()方法,这个方法主要是对路由信息的封装类Postcard的完善,再跳转过程中,通过调用completion()方法,通过RouteMeta完善路由信息

public synchronized static void completion(Postcard postcard) {
    if (null == postcard) {
        throw new NoRouteFoundException(TAG + "No postcard!");
    }

    //首先查找路由信息是否已经加载到Warehouse.routes映射里面
    RouteMeta routeMeta = Warehouse.routes.get(postcard.getPath());
    if (null == routeMeta) {    // 如果为null,那么可能为空,也可能是还没把对应的路由装载进来,Arouter是分组装载,在初始化是只会加载包含分组映射类Class的信息,然后根据分组再加载分组内详细的路由信息
        Class<? extends IRouteGroup> groupMeta = Warehouse.groupsIndex.get(postcard.getGroup());  // 得到包含分组路由信息的类Class的
        if (null == groupMeta) {
        //如果没有对应分组类,则抛出异常
            throw new NoRouteFoundException(TAG + "There is no route match the path [" + postcard.getPath() + "], in group [" + postcard.getGroup() + "]");
        } else {
            // Load route and cache it into memory, then delete from metas.
            try {
                if (ARouter.debuggable()) {
                    logger.debug(TAG, String.format(Locale.getDefault(), "The group [%s] starts loading, trigger by [%s]", postcard.getGroup(), postcard.getPath()));
                }

                IRouteGroup iGroupInstance = groupMeta.getConstructor().newInstance();
                //把包含分组路由信息的映射装载进Warehouse.routes
                iGroupInstance.loadInto(Warehouse.routes);
                //移除分组group信息
                Warehouse.groupsIndex.remove(postcard.getGroup());

                if (ARouter.debuggable()) {
                    logger.debug(TAG, String.format(Locale.getDefault(), "The group [%s] has already been loaded, trigger by [%s]", postcard.getGroup(), postcard.getPath()));
                }
            } catch (Exception e) {
                throw new HandlerException(TAG + "Fatal exception when loading group meta. [" + e.getMessage() + "]");
            }

            completion(postcard);   // 重新继续完善
        }
    } else {
    //把RouteMeta的相关属性设置给PostCard对象
        postcard.setDestination(routeMeta.getDestination());
        postcard.setType(routeMeta.getType());
        postcard.setPriority(routeMeta.getPriority());
        postcard.setExtra(routeMeta.getExtra());

        Uri rawUri = postcard.getUri();
        if (null != rawUri) {   // 把Uri携带的参数信息解析出来,放进Bundle对象
            Map<String, String> resultMap = TextUtils.splitQueryParameters(rawUri);
            Map<String, Integer> paramsType = routeMeta.getParamsType();

            if (MapUtils.isNotEmpty(paramsType)) {
                // Set value by its type, just for params which annotation by @Param
                for (Map.Entry<String, Integer> params : paramsType.entrySet()) {
                    setValue(postcard,
                            params.getValue(),
                            params.getKey(),
                            resultMap.get(params.getKey()));
                }

                // Save params name which need auto inject.
                postcard.getExtras().putStringArray(ARouter.AUTO_INJECT, paramsType.keySet().toArray(new String[]{}));
            }

            // Save raw uri
            postcard.withString(ARouter.RAW_URI, rawUri.toString());
        }

        switch (routeMeta.getType()) {
            case PROVIDER:  // 如果@Route的注解类型是服务提供者IProvider
                // 获取想要获取当前IProvider的Class类型
                Class<? extends IProvider> providerMeta = (Class<? extends IProvider>) routeMeta.getDestination();
                //获取当前类型的实例,如果没有实例的则进行初始化,构造出IProvider
                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());
                    }
                }
                postcard.setProvider(instance);//把instance设置给postcard
                postcard.greenChannel();    //provider默认走绿色通道,不用经过拦截器
                break;
            case FRAGMENT:
                postcard.greenChannel();    // Fragment类型也不需要经过拦截器
            default:
                break;
        }
    }
}

completion()做的主要工作就是找到路由类的RouteMeta对象,来完善Postcard信息

  1. 根据path信息在Warehouse.routes里面查找是否含有相应的RouteMeta信息
  2. 如果没有RouteMeta信息,那么可能是对应的分组路由的映射还没加载进内存,所以就继续查找包含分组信息映射的类,实例化对应的IRouteGroup类,把这个分组的映射关系全部加载进来,然后把Warehouse.groupsIndex移除响应分组类,装载完成后再次调用completion(),完善postcard信息
  3. 如果已经有RouteMeta信息,那么就把对应的RouteMeta的信息设置给postcard,如果uri携带了参数信息,就把参数信息全部装进bundle
  4. 如果获取的类型为PROVIDER或者FRAGMENT,那么就会开启绿色通道,不再走拦截器服务。
  5. 如果PROVIDER类型,对于Provider的理解是服务提供者,主要用于一个组件来向另一个组件提供服务,所以一个Class类型的的服务只有一个实例。首先会从Warehouse.providers里面获取对应的实例,如果没有,那么就初始化,然后放入Warehouse.providers映射里面。最终给postcard设置provider

下面再看下_ARouter.afterInit();方法

static void afterInit() {
    // 根据Arouter用法,根据path找实例,拿到InterceptorService
    interceptorService = (InterceptorService) ARouter.getInstance().build("/arouter/service/interceptor").navigation();
}

afterInit()主要是在装载完所有的路由映射后执行的操作,获取拦截器服务InterceptorService
而InterceptorService是一个IProvier,获取拦截器服务InterceptorService的过程用的还是Arouter的方式,下面再看下Arouter获取IProvider的方式,上面的方法最终会调用到_Arouter的navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback)方法

protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
    ...

    try {
        LogisticsCenter.completion(postcard);
    } catch (NoRouteFoundException ex) {
        logger.warning(Consts.TAG, ex.getMessage());

        if (debuggable()) {
            // Show friendly tips for user.
            runInMainThread(new Runnable() {
                @Override
                public void run() {
                    Toast.makeText(mContext, "There's no route matched!\n" +
                            " Path = [" + postcard.getPath() + "]\n" +
                            " Group = [" + postcard.getGroup() + "]", Toast.LENGTH_LONG).show();
                }
            });
        }

        if (null != callback) {
        //回调onLost()
            callback.onLost(postcard);
        } else {
        //如果没有回调Callback,就会调用查找是否有降级服务,如果有则执行降级
            DegradeService degradeService = ARouter.getInstance().navigation(DegradeService.class);
            if (null != degradeService) {
                degradeService.onLost(context, postcard);
            }
        }

        return null;
    }

    if (null != callback) {
    //  回调onFound()
        callback.onFound(postcard);
    }

//非绿色通道
    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
             */
            @Override
            public void onContinue(Postcard postcard) {
                _navigation(context, postcard, requestCode, callback);
            }

            /**
             * Interrupt process, pipeline will be destory when this method called.
             */
            @Override
            public void onInterrupt(Throwable exception) {
                if (null != callback) {
                    callback.onInterrupt(postcard);
                }

                logger.info(Consts.TAG, "Navigation failed, termination by interceptor : " + exception.getMessage());
            }
        });
    } else {
        //绿色通道
        return _navigation(context, postcard, requestCode, callback);
    }

    return null;
}
  1. 调用LogisticsCenter.completion(postcard)把PostCard的相关属性信息全部完善
  2. 非绿色通道,调用拦截器服务interceptorService,如果拦截器全部通过的话,就执行_navigation(),如果拦截器执行拦截,会回调callback.onInterrupt()
  3. 绿色通道,直接调用_navigation()方法

因为completion()已经在上面介绍过了,拦截器服务的相关方法,放在下面再分析,继续追踪_navigation(),也是路由跳转的最后一步了

private Object _navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
//如果传入的context为null,那么就会用Application
    final Context currentContext = null == context ? mContext : context;

    switch (postcard.getType()) {
    //如果是activity的路由类型
        case ACTIVITY:
            // 构建Intent
            final Intent intent = new Intent(currentContext, postcard.getDestination());
            //把bundle设置进intent
            intent.putExtras(postcard.getExtras());

            // Set flags.
            int flags = postcard.getFlags();
            if (-1 != flags) {
                intent.setFlags(flags);
            } else if (!(currentContext instanceof Activity)) {    // Non activity, need less one flag.
            //如果传入的context不是activity,那么启动Activity就会传入Intent.FLAG_ACTIVITY_NEW_TASK创建一个新的栈
                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            }

            // Set Actions
            String action = postcard.getAction();
            if (!TextUtils.isEmpty(action)) {
                intent.setAction(action);
            }

            // 之前说过了拦截器的执行是异步的,这里就切回主线程做startActivity
            runInMainThread(new Runnable() {
                @Override
                public void run() {
                    startActivity(requestCode, currentContext, intent, postcard, callback);
                }
            });

            break;
        case PROVIDER:
        //如果路由类型为Provider,就直接返回IProcier对象
            return postcard.getProvider();
        case BOARDCAST:
        case CONTENT_PROVIDER:
        case FRAGMENT:
        //如果是BOARDCAST,CONTENT_PROVIDER,FRAGMENT类型
            Class fragmentMeta = postcard.getDestination();
            try {
            //实例化对象
                Object instance = fragmentMeta.getConstructor().newInstance();
                //如果是Fragment的话,设置传递过来的参数
                if (instance instanceof Fragment) {
                    ((Fragment) instance).setArguments(postcard.getExtras());
                } else if (instance instanceof android.support.v4.app.Fragment) {
                    ((android.support.v4.app.Fragment) instance).setArguments(postcard.getExtras());
                }

                return instance;
            } catch (Exception ex) {
                logger.error(Consts.TAG, "Fetch fragment instance error, " + TextUtils.formatStackTrace(ex.getStackTrace()));
            }
        case METHOD:
        case SERVICE:
        default:
            return null;
    }

    return null;
}
  1. 先查看是否context是否为null,如果为null,则赋值为application
  2. 如果是activity类型,就会构造出intent,把相应的参数等信息全部带上。如果context不是activity会给intent设置Intent.FLAG_ACTIVITY_NEW_TASK,创建新的任务栈。因为拦截器的服务是在一步线程做的,所以最后的startActivity会切回主线程
  3. 如果是IProvider类型,那么就直接返回相应Iprovider
  4. 如果是Fragment类型。会实例化,然后把相关参数设置给fragment,最终返回相应实例

好了,通过上面的分析,已经把路由的跳转流程分析了一遍。具体的路由信息的装载,编译期对注解的处理等还没说。下面再把拦截器的部分分析一下

Interceptor

Arouter中的拦截器是全局,通过拦截器服务启动,下面看下拦截器服务InterceptorServiceImpl
先看下类继承结构InterceptorServiceImpl implements InterceptorService
而InterceptorService extends IProvider,所以InterceptorServiceImpl就是一个IProvider。并且IInterceptor extends IProvider,所以拦截器IInterceptor也是单例,即服务提供者

private static boolean interceptorHasInit;//服务是否初始化完成
private static final Object interceptorInitLock = new Object();//拦截器初始化锁,保证服务在初始化完成后启动

接着看一下init()方法,由于InterceptorServiceImpl是IProvider,所以会在第一次初始化的时候就会调用init()方法

@Override
public void init(final Context context) {
//调用线程池异步执行任务
    LogisticsCenter.executor.execute(new Runnable() {
        @Override
        public void run() {
        //判断拦截器索引Warehouse.interceptorsIndex是否为空,即是否有拦截器
            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();
                        //调用拦截器的init方法
                        iInterceptor.init(context);
                        //把初始化好的拦截器添加进拦截器列表Warehouse.interceptors中
                        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.");
                
                    //把等待获取interceptorInitLock锁的线程唤醒
                synchronized (interceptorInitLock) {
                    interceptorInitLock.notifyAll();
                }
            }
        }
    });
}
  1. 异步执行初始化任务,首先判断拦截索引Warehouse.interceptorsIndex是否为空,即是否有拦截器
  2. 遍历拦截器索引列表,实例化每个拦截器,并调用拦截器的init()方法,然后把初始化好的IInterceptor添加进拦截器列表Warehouse.interceptors
  3. 把interceptorHasInit置为true,唤醒正在等待获取interceptorInitLock锁的线程

Warehouse.interceptorsIndex里面的数据是在LogisticsCenter的init()方法里面被赋值的

下面再看看拦截器服务里面的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() {
            //可取消的CountDownLatch,countDown的值为拦截器的数量
                CancelableCountDownLatch interceptorCounter = new CancelableCountDownLatch(Warehouse.interceptors.size());
                try {
                //开始执行第一个拦截器的拦截,这个方法会一直调用拦截器列表中下一个拦截器的拦截
                    _excute(0, interceptorCounter, postcard);
                    //interceptorCounter等待,如果超时300s还没有执行完,这个方法也会返回
                    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.
                    //如果tag有值,tag是用来携带拦截过程中抛出的异常
                        callback.onInterrupt(new HandlerException(postcard.getTag().toString()));
                    } else {
                    //如果上面的情况都没有,那就是正常的返回,所有的拦截方法都执行完了,就继续执行,回调onContinue
                        callback.onContinue(postcard);
                    }
                } catch (Exception e) {
                    callback.onInterrupt(e);
                }
            }
        });
    } else {
    //没有拦截器的话,就继续执行,回调onContinue
        callback.onContinue(postcard);
    }
}
  1. 首先阻塞等待拦截器服务是否初始化完成
  2. 初始化完成后,创建CancelableCountDownLatch,countDown的值为拦截器的列表,调用_excute(0, interceptorCounter, postcard);开始执行每一个拦截器的拦截方法。
  3. 如果interceptorCounter.await()返回了,如果interceptorCounter的值还没归0,就代表是超时返回,那么就执行拦截回调,调用callback.onInterrupt()。
  4. 如果interceptorCounter不是超时返回,就代表是正常返回,那么就判断postcard的tag是否有值,如果在拦截过程中需要拦截,那么就需要给tag赋值。所以tag不为null的话,就表示出了异常,需要拦截,执行回调callback.onInterrupt()
  5. 如果tag为null,那么就是正常情况,执行回调callback.onContinue()

下面在继续分析_excute()方法,分析下拦截器如何一个个往下传的

//index :在拦截器列表中的索引值
//CancelableCountDownLatch : 传进来的CountDownLatch,用于在拦截时,快速清零返回
// postcard : postcard对象,发生拦截时会给postcard的tag字段赋值

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() {
        //如果上一个拦截器执行完了,那么允许接着执行下一个拦截的话,就回调onContinue方法
            @Override
            public void onContinue(Postcard postcard) {
                //上一个拦截器顺利通过,counter调用countDown把值减一
                counter.countDown();
                // 执行下一个拦截器,索引值加1
                _excute(index + 1, counter, postcard);  
            }
            
            //如果不允许执行下一个拦截器的话,就回调onInterrupt()方法,进行打断拦截
            @Override
            public void onInterrupt(Throwable exception) {
                //上一个拦截器发生了拦截,给postcard的tag赋值

                postcard.setTag(null == exception ? new HandlerException("No message.") : exception.getMessage());    // save the exception message for backup.
                //对counter清零,是其立刻返回
                counter.cancel();
               
            }
        });
    }
}
  1. 获取对应索引值的拦截器,执行process()方法,并且传入回调InterceptorCallback
  2. 如果拦截器顺利执行,回调onCotinue(),counter减一,继续执行下一个拦截器
  3. 如果拦截器拦截,回调onInterrupt(),给postcard的tag赋值,counter清零,立刻返回结束counter的等待

拦截器服务的内容页分析完了

上一篇下一篇

猜你喜欢

热点阅读