ARouter 路由框架源码解析

作者: SharryChoo | 来源:发表于2018-08-10 19:01 被阅读64次

    前言

    随着项目业务逻辑和功能点日益递增, 逻辑的耦合程度也逐渐升高, 组件化技术可以很好的解决这个问题, 公司大佬最近也在搞组件化工程, 我想是时候分析一下组件化的实现方案了, Alibaba 的 ARouter 是非常出名的一个库, 笔者抱着学习的态度去了解其实现原理, 以便于对组件化有更深刻的了解.

    GitHub

    https://github.com/alibaba/ARouter

    一. ARouter 的模块区分

    arouter-annotation

    • @Router
      • 作用在 Activity 上会在对应的 Module 上生成 ARouterGroupgroup_name1 类
      • 作用在 IProvider 接口的实现类上会在对应的 Module 上生成 ARouterProvidermodule_name 类
    /**
     * Mark a page can be route by router.
     *
     * @author Alex <a href="mailto:zhilong.liu@aliyun.com">Contact me.</a>
     * @version 1.0
     * @since 16/8/15 下午9:29
     */
    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.CLASS)
    public @interface Route {
    
        /**
         * 跳转地址
         */
        String path();
    
        /**
         * 跳转地址所属的组, 必须是通用的组名(一般不填/或者填写当前 module 名)
         */
        String group() default "";
    
        /**
         * 用于生成 java 文档名(可忽略) 
         */
        String name() default "";
    
        /**
         * Extra data, can be set by user.
         * Ps. U should use the integer num sign the switch, by bits. 10001010101010
         */
        int extras() default Integer.MIN_VALUE;
    
        /**
         * 路由的优先级, 用于拦截路由的分发
         */
        int priority() default -1;
    }
    
    • @Interceptor
      • 作用在 IInterceptor 的实现类上会在对应的 Module 上生成 ARouterProvidermodule_name 类
    /**
     * Mark a interceptor to interception the route.
     * BE ATTENTION : This annotation can be mark the implements of #{IInterceptor} ONLY!!!
     *
     * @author Alex <a href="mailto:zhilong.liu@aliyun.com">Contact me.</a>
     * @version 1.0
     * @since 16/8/23 14:03
     */
    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.CLASS)
    public @interface Interceptor {
        /**
         * The priority of interceptor, ARouter will be excute them follow the priority.
         */
        int priority();
    
        /**
         * The name of interceptor, may be used to generate javadoc.
         */
        String name() default "Default";
    }
    

    arouter-compiler

    编译时注解的扫描与相关类的生成

    arouter-api

    提供路由的基本服务

    • ARouter
      • 门面
    • _ARouter
      • 实现
    • LogisticsCenter
      • 逻辑中心
    • Postcard
      • 导航的明信片
    • Warehouse
      • 数组仓库

    整体模块之间的依赖关系

    graph TB
    arouter-api-->arouter-annotation
    arouter-compiler-->arouter-annotation
    

    接下来开始分析 ARouter 的工作流程

    二. 路由的初始化

    • 调用方式在 Application 中调用 ARouter.init(this);
    • 接下来分析一下路由初始化的源码
        /**
         * ARouter.init
         */
        public static void init(Application application) {
            if (!hasInit) {
                // 用于 ARouter 的 logger 打印, 之后会忽略这部分的源码
                logger = _ARouter.logger;
                _ARouter.logger.info(Consts.TAG, "ARouter init start.");
                // 1. 调用了 _ARouter 中的 init 
                hasInit = _ARouter.init(application);
                if (hasInit) {
                    // 2. 调用 _ARouter 中的 afterInit 处理初始化之后的相关操作
                    _ARouter.afterInit();
                }
            }
        }
    

    可以看到 ARouter 其实就是个外壳, 具体的实现均由 _ARouter 提供,
    可见路由的初始化分为两步进行

    • 调用 _ARouter 的 init 执行初始化操作
    • 调用了 _ARouter 的 afterInit() 执行善后操作

    先从 _ARouter.init 开始

    1. _ARouter.init

        /**
         * _ARouter.init
         */
        protected static synchronized boolean init(Application application) {
            mContext = application;
            // 1. 调用了 LogisticsCenter 的 init 方法
            LogisticsCenter.init(mContext, executor);
            // 2. 更新标记位
            hasInit = true;
            // 3. 绑定主线程的 Handler
            mHandler = new Handler(Looper.getMainLooper());
            return true;
        }
    

    主要做了三件事情

    • 调用了 LogisticsCenter 的 init 方法
    • 标记为已经初始化完毕
    • 创建主线程的 Handler

    接下来分析一下 LogisticsCenter 初始化做了哪些事情

    1.1 LogisticsCenter 逻辑处理中心的初始化

        /**
         * LogisticsCenter.init, load all metas in memory. Demand initialization
         */
        public synchronized static void init(Context context, ThreadPoolExecutor tpe) throws HandlerException {
            mContext = context;
            // 给线程池赋值
            executor = tpe;
            try {
                // 尝试使用插件注册 ARouter 
                loadRouterMap();
                
                if (registerByPlugin) {
                    // ...
                } else {
                    // 这里我们着重分析非插件注册的初始化实现
                    Set<String> routerMap;
                    // 1. 判断是否是调试(调试会生成类), 若是调试, 则从生成文件夹下找寻生成类
                    if (ARouter.debuggable() || PackageUtils.isNewVersion(context)) {
                        // 1.1 每次调试, 会通过编译时注解, 生成相关文件保存到本地 com.alibaba.android.arouter.routes 文件夹下
                        // 当程序运行时, 通过 getFileNameByPackageName 找到对应的全限定名
                        routerMap = ClassUtils.getFileNameByPackageName(mContext, ROUTE_ROOT_PAKCAGE);
                        if (!routerMap.isEmpty()) {
                            // 1.2 更新生成文件的集合
                            context.getSharedPreferences(AROUTER_SP_CACHE_KEY, Context.MODE_PRIVATE).edit()
                                    .putStringSet(AROUTER_SP_KEY_MAP, routerMap)
                                    .apply();
                        }
                        PackageUtils.updateVersion(context);    // Save new version name when router map update finishes.
                    } else {
                        // 2. 若不是调试, 则直接从本地的缓存中获取, 非调试环境, 不会生成新的代码
                        routerMap = new HashSet<>(
                             context.getSharedPreferences(AROUTER_SP_CACHE_KEY, Context.MODE_PRIVATE)
                                    .getStringSet(AROUTER_SP_KEY_MAP, new HashSet<String>())
                        );
                    }
                    // 3. 遍历集合, 将缓存的集合加载进相应的集合中
                    for (String className : routerMap) {
                        if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_ROOT)) {
                            // 3.1 加载根元素(com.alibaba.android.arouter.routes.ARouter$$Root$$XXX)
                            ((IRouteRoot) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.groupsIndex);
                        } else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_INTERCEPTORS)) {
                            // 3.2 加载拦截器标签元素(com.alibaba.android.arouter.routes.ARouter$$Interceptors$$XXX)
                            ((IInterceptorGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.interceptorsIndex);
                        } else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_PROVIDERS)) {
                            // 3.3 加载提供器元素(com.alibaba.android.arouter.routes.ARouter$$Providers$$XXX)
                            ((IProviderGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.providersIndex);
                        }
                    }
                }
                // ...忽略日志代码
            } catch (Exception e) {
                // ...忽略异常代码
            }
        }
        
        /**
         * LogisticsCenter.loadRouterMap 若启用了插件注册 ARouter , 将会在这个方法中自动生成代码
         */
        private static void loadRouterMap() {
            registerByPlugin = false;
            //auto generate register code by gradle plugin: arouter-auto-register
            // looks like below:
            // registerRouteRoot(new ARouter..Root..modulejava());
            // registerRouteRoot(new ARouter..Root..modulekotlin());
        }
        
        /**
         * Warehouse : ARouter 的数据仓库
         */
        class Warehouse {
            // Cache route and metas
            static Map<String, Class<? extends IRouteGroup>> groupsIndex = new HashMap<>();
            static Map<String, RouteMeta> routes = new HashMap<>();
    
            // Cache provider
            static Map<Class, IProvider> providers = new HashMap<>();
            static Map<String, RouteMeta> providersIndex = new HashMap<>();
    
            // Cache interceptor
            static Map<Integer, Class<? extends IInterceptor>> interceptorsIndex = new UniqueKeyTreeMap<>("More than one interceptors use same priority [%s]");
            static List<IInterceptor> interceptors = new ArrayList<>();
    
            static void clear() {
                routes.clear();
                groupsIndex.clear();
                providers.clear();
                providersIndex.clear();
                interceptors.clear();
                interceptorsIndex.clear();
            }
       }
    

    通过 LogisticsCenter.init 的分析, 可知该方法起到了非常重要的作用, 主要做了以下工作

    • 尝试通过插件去注册 ARouter, 这里忽略
    • 获取 Set<String> routerMap 的数据
      • Debug: 若是开发环境, 则会读取编译时注解在 com.alibaba.android.arouter.routes 文件夹下的生成文件, 添加到 routerMap 中
        • 不为空, 则通过 SharedPreferences 缓存到本地
      • Release: 若线上环境, 则直接从缓存中读取
    • 遍历 routerMap 集合
      • 反射实例化 com.alibaba.android.arouter.routes.ARouterRootXXX 对象, 调用 loadInto 添加到 Warehouse.groupsIndex 中
      • 反射实例化 com.alibaba.android.arouter.routes.ARouterInterceptorsXXX 对象, 调用 loadInto 添加到 Warehouse.interceptorsIndex 中
      • 反射实例化 com.alibaba.android.arouter.routes.ARouterProvidersXXX 对象, 调用 loadInto 添加到 Warehouse.providersIndex 中

    1.2 生成类展示

    /**
     * CreateTime: @Router 注解作用在类上时, 被生成
     * Description: 
     * 将所有被 @Router(path="", group="m2") 注解标记并且 group = m2 的类, 添加到 Warehouse.routes 中
     * Warehouse.routes(key = @Router中的path, value = @Router标记类的信息生成的RouteMeta对象)
     */
    public class ARouter$$Group$$m2 implements IRouteGroup {
        @Override
        public void loadInto(Map<String, RouteMeta> atlas) {
            atlas.put("/module/2", RouteMeta.build(RouteType.ACTIVITY, TestModule2Activity.class, "/module/2", "m2", null, -1, -2147483648));
        }
    }
    
    /**
     * CreateTime: 一个 Module 中若有 ARouter$$Group$$XXX 存在时, 被生成
     * Description: 
     * 收集一个 Module 下所有的 ARouter$$Group$$XXX 添加到 Warehouse.groupsIndex 中
     * Warehouse.groupsIndex (key = Group名, value = ARouter$$Group$$XXX.class)
     */
    public class ARouter$$Root$$modulejava implements IRouteRoot {
        @Override
        public void loadInto(Map<String, Class<? extends IRouteGroup>> routes) {
            routes.put("m2", ARouter$$Group$$m2.class);
        }
    }
    
    
    /**
     * CreateTime: @Router 注解作用在实现了 IProvider 的类上时, 被生成
     * Description: 
     * 收集一个 Module 下所有的 IProvider 实现类信息添加到 Warehouse.providersIndex 中
     * Warehouse.providersIndex(key = 实现的接口类的全限定名, value = @Router标记类的信息生成的RouteMeta对象);
     */
    public class ARouter$$Providers$$app implements IProviderGroup {
        @Override
        public void loadInto(Map<String, RouteMeta> providers) {
            providers.put("com.alibaba.android.arouter.demo.testservice.HelloService",
                    RouteMeta.build(RouteType.PROVIDER, HelloServiceImpl.class, "/service/hello", "service", null, -1, -2147483648)
            );
        }
    }
    
    
    /**
     * CreateTime: @Interceptor 注解作用在实现了 IInterceptor 的类上时, 被生成
     * Description: 
     * 收集一个 Module 下所有的 IInterceptorGroup 实现类信息添加到 Warehouse.interceptorsIndex 中
     * Warehouse.interceptorsIndex (key = @Interceptor中的优先级信息, value = 实现类的类型)
     */
    public class ARouter$$Interceptors$$app implements IInterceptorGroup {
        @Override
        public void loadInto(Map<Integer, Class<? extends IInterceptor>> interceptors) {
            interceptors.put(7, Test1Interceptor.class);
        }
    }
    

    1.3 生成类之间的依赖关系

    • IRouteRoot 与 IRootGroup 之间的依赖关系

      • 一个 module 会生成一个 ARouterRootmodule_name 类

      • 一个 module 会根据 group 的不同, 生成多个 ARouterRootgroup_name 类

      • ARouterRootmodule_name.loadInto() 方法被调用时, 会将保存的 ARouterRootgroup_name.class 信息注入 Warehouse.groupsIndex 中

      • 通过 Warehouse.groupsIndex 可以找到 ARouterRootgroup_name 类

        • 实例化后调用其 ARouterRootgroup_name.loadInto() , 会将 @Route 标记类的信息注入 Warehouse.routes 中, 这是非常重要的一步, 在后面会展开分析
      • IRouteRoot 与 IRootGroup 之间的依赖关系.png
    • IProvider 生成类

      • IProvider 生成类.png
    • IInterceptor 生成类

      • IInterceptor 生成类.png

    2. _ARouter.afterInit

        static void afterInit() {
            // 初始化拦截服务
            interceptorService = (InterceptorService) ARouter.getInstance()
                .build("/arouter/service/interceptor")
                .navigation();
        }
    

    2.1 从 ARouter.build 方法开始分析

        /**
         * ARouter.build 
         */
        public Postcard build(String path) {
            return _ARouter.getInstance().build(path);
        }
    
        /**
         * ARouter.build 
         */
        @Deprecated
        public Postcard build(String path, String group) {
            return _ARouter.getInstance().build(path, group);
        }
    
        /**
         * ARouter.build 
         */
        public Postcard build(Uri url) {
            return _ARouter.getInstance().build(url);
        }
    

    可以看到三个重载方法都调用了 _ARouter 的方法, 这里与 WindowManager 中的方法使用 WindowManagerGlobal 桥接的手法很类似

        /**
         * _ARouter.build
         * 使用默认的 Group 组, 构建 Postcard 明信片
         */
        protected Postcard build(String path) {
            if (TextUtils.isEmpty(path)) {
                throw new HandlerException(Consts.TAG + "Parameter is invalid!");
            } else {
                // 1. 获取 PathReplaceService 服务
                PathReplaceService pService = ARouter.getInstance().navigation(PathReplaceService.class);
                if (null != pService) {
                    path = pService.forString(path);
                }
                // 调用 extractGroup 方法从 path 获取路由的 group, 调用了重载方法
                return build(path, extractGroup(path));
            }
        }
    
        /**
         * _ARouter.build
         * 通过 Uri 来构建 Postcard 明信片
         */
        protected Postcard build(Uri uri) {
            if (null == uri || TextUtils.isEmpty(uri.toString())) {
                throw new HandlerException(Consts.TAG + "Parameter invalid!");
            } else {
                // 1. 获取 PathReplaceService 服务
                PathReplaceService pService = ARouter.getInstance().navigation(PathReplaceService.class);
                if (null != pService) {
                    uri = pService.forUri(uri);
                }
                // 2. 通过 path/group/uri 来构建明信片
                return new Postcard(uri.getPath(), extractGroup(uri.getPath()), uri, null);
            }
        }
    
        /**
         * _ARouter.build
         * 通过路径和指定的 group(用于合并路由) 构建明信片
         */
        protected Postcard build(String path, String group) {
            if (TextUtils.isEmpty(path) || TextUtils.isEmpty(group)) {
                throw new HandlerException(Consts.TAG + "Parameter is invalid!");
            } else {
                // 1. 获取 PathReplaceService 服务
                PathReplaceService pService = ARouter.getInstance().navigation(PathReplaceService.class);
                if (null != pService) {
                    path = pService.forString(path);
                }
                // 2. 通过 path / group 来构建明信片
                return new Postcard(path, group);
            }
        }
    

    通过 _ARouter.build 重载方法可知有一个非常重要的点 通过调用 ARouter.navigation(PathReplaceService.class) 获取了一个 PathReplaceService 服务, 接下来看看这个服务获取的流程

        /**
         * ARouter.navigation
         */
        public <T> T navigation(Class<? extends T> service) {
            return _ARouter.getInstance().navigation(service);
        }
        
        /**
         * _ARouter.navigation
         */
        protected <T> T navigation(Class<? extends T> service) {
            try {
                // 1 通过全限定类名尝试获取 service 的 Postcard
                Postcard postcard = LogisticsCenter.buildProvider(service.getName());
                if (null == postcard) {
                    // 尝试通过简单类名获取 Postcard
                    postcard = LogisticsCenter.buildProvider(service.getSimpleName());
                }
                // 2. 没找到则返回 null
                if (null == postcard) {
                    return null;
                }
                // 3. 找到了则调用 LogisticsCenter.completion 对这个 postcard 进行数据填充
                LogisticsCenter.completion(postcard);
                // 4. 通过 postcard.getProvider() 返回数据
                return (T) postcard.getProvider();
            } catch (NoRouteFoundException ex) {
                // ...
            }
        }
        
        /**
         * LogisticsCenter.buildProvider
         */
        public static Postcard buildProvider(String serviceName) {
            // Warehouse.providersIndex 在 LogisticsCenter.init 中进行数据注入, 在上面已经分析过
            // 通过 serviceName 获取对应类的信息封装对象 RouteMeta
            RouteMeta meta = Warehouse.providersIndex.get(serviceName);
            if (null == meta) {
                return null;
            } else {
                // 构建明信片
                return new Postcard(meta.getPath(), meta.getGroup());
            }
        }
    

    可以看到 _ARouter.navigation 中主要处理了以下事务

    • 调用 LogisticsCenter.buildProvider 获取要获取服务的 Postcar
      • 通过 Warehouse.providersIndex 找到对应的 RouteMeta 对象 meta
      • 使用 meta 来构建 Postcard 对象
    • 没找到则返回 null
    • 找到相应的 Postcard 则调用 LogisticsCenter.completion 对这个 Postcard 进行数据填充
      • LogisticsCenter.completion 这个方法非常重要, 放在后面分析
    • 经过 LogisticsCenter.completion 对 Postcard 进行数据填充之后, Postcard 中的 provider 就有了数据, 调用 Postcard.getProvider() 将所需服务对象返回

    PathReplaceService 不为空的话, 会调用其 forString(path)/forUri(uri) 进行自定义解析(一般为空, ARouter 默认没有实现这个接口)

    小结

    至此 ARouter.build 完成之后获取到了一个 Postcard 对象, 然后会调用 Postcard.navigation() 获取所需对象实例, 接下来分析一下 Postcard.navigation() 的流程

    2.2 分析 Postcard.navigation() 方法流程

        /**
         * Postcard.navigation
         */
        public Object navigation() {
            return navigation(null);
        }
    
        /**
         * Postcard.navigation
         */
        public Object navigation(Context context) {
            return navigation(context, null);
        }
    
        /**
         * Postcard.navigation
         */
        public Object navigation(Context context, NavigationCallback callback) {
            // 最终还是回到了 ARouter.navigation 方法中
            return ARouter.getInstance().navigation(context, this, -1, callback);
        }
    

    可以看到 Postcard.navigation 的一系列重载方法, 最终都会调用到 ARouter.navigation 中, 这里才是重头戏的开始

    接下来分析 ARouter.navigation(context, this, -1, callback) 这个方法的处理了哪些事务

        /**
         * ARouter.navigation
         */
        public Object navigation(Context mContext, Postcard postcard, int requestCode, NavigationCallback callback) {
            return _ARouter.getInstance().navigation(mContext, postcard, requestCode, callback);
        }
        
        /**
         * _ARouter.navigation
         */
        protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
            try {
                // 1. 通过 postcard 明信片, 进行导航查找
                LogisticsCenter.completion(postcard);
            } catch (NoRouteFoundException ex) {
                // ...回调一些没有找到目标的操作
                return null;
            }
            // 2. 回调通过 postcard 明信片定位到了目标
            if (null != callback) {
                callback.onFound(postcard);
            }
            // 3. 判断 postcard 是否为绿色通道, 若不是则启动拦截器服务进行拦截
            if (!postcard.isGreenChannel()) {   // 必须运行在异步线程, 否则可能 ANR
                interceptorService.doInterceptions(postcard, new InterceptorCallback() {
                    @Override
                    public void onContinue(Postcard postcard) {
                        _navigation(context, postcard, requestCode, callback);
                    }
    
                    @Override
                    public void onInterrupt(Throwable exception) {
                        if (null != callback) {
                            callback.onInterrupt(postcard);
                        }
                    }
                });
                
            } else {
                // 4. 回调 _navigation 方法
                return _navigation(context, postcard, requestCode, callback);
            }
            return null;
        }
    
        /**
         * _ARouter._navigation
         */
        private Object _navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
            final Context currentContext = null == context ? mContext : context;
            switch (postcard.getType()) {
                // 4.1 处理 Activity 的导航
                case ACTIVITY:
                    // 4.1.1 构建 Intent 意图
                    final Intent intent = new Intent(currentContext, postcard.getDestination());
                    intent.putExtras(postcard.getExtras());
                    // 4.1.2 获取并设置 Flags
                    int flags = postcard.getFlags();
                    if (-1 != flags) {
                        intent.setFlags(flags);
                    } else if (!(currentContext instanceof Activity)) {    // Non activity, need less one flag.
                        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    }
                    // 4.1.3 设置 Intent 的 Action
                    String action = postcard.getAction();
                    if (!TextUtils.isEmpty(action)) {
                        intent.setAction(action);
                    }
                    // 4.1.4 在主线程中处理 Activity 的启动
                    if (Looper.getMainLooper().getThread() != Thread.currentThread()) {
                        mHandler.post(new Runnable() {
                            @Override
                            public void run() {
                                startActivity(requestCode, currentContext, intent, postcard, callback);
                            }
                        });
                    } else {
                        startActivity(requestCode, currentContext, intent, postcard, callback);
                    }
                    break;
                // 4.2 处理 PROVIDER("com.alibaba.android.arouter.facade.template.IProvider") 的导航
                case PROVIDER:
                    return postcard.getProvider();
                // 4.3 处理 BOARDCAST/CONTENT_PROVIDER/FRAGMENT 的导航
                case BOARDCAST:
                case CONTENT_PROVIDER:
                case FRAGMENT:
                    Class fragmentMeta = postcard.getDestination();
                    try {
                        // 4.3.1 反射创建 Fragment 对象
                        Object instance = fragmentMeta.getConstructor().newInstance();
                        // 4.3.2 给 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) {
                        // ...
                    }
                // 4.4 处理 METHOD/SERVICE 的导航
                case METHOD:
                case SERVICE:
                default:
                    return null;
            }
    
            return null;
        }
    

    通过上面的源码分析可以非常清晰的看到 _ARouter.navigation 主要做了以下的事情

    • 调用 LogisticsCenter.completion 方法, 对 postcard 明信片数据填充
    • 回调通过 postcard 明信片定位到了目标
    • 判断 postcard 是否为绿色通道, 若不是则启动拦截器服务进行拦截
    • 回调 _navigation 方法真正的执行导航
      • 处理 Activity 的跳转
      • 处理 ARouter IProvider 的服务获取
      • 处理 BOARDCAST/CONTENT_PROVIDER/FRAGMENT 的导航
      • 处理 METHOD/SERVICE 的导航

    小结

    可以看到 ARouter.navigation(context, this, -1, callback) 中最终会调用 LogisticsCenter.completion 进行数据注入, 前面 2.1 中提到 ARouter.navigation(Class<? extends T> service) 同样也调用了这个方法, 其重要程度可见一斑

    接下来我们看一下, 最后的操作, LogisticsCenter.completion 中到底对 Postcard 做了哪些操作

    2.4 LogisticsCenter.completion

        /**
         * LogisticsCenter.completion
         */
        public synchronized static void completion(Postcard postcard) {
            if (null == postcard) {
                throw new NoRouteFoundException(TAG + "No postcard!");
            }
            // 1. 从缓存池中 Warehouse.routes 获取对应的 ARouter$$Group$$xxx.class 类的信息封装对象 routeMeta
            // 初始化的时候, 一定为 null, 在 LogisticsCenter.init 中, 只对 Warehouse.groupsIndex 进行了数据填充
            RouteMeta routeMeta = Warehouse.routes.get(postcard.getPath());
            if (null == routeMeta) {
                // 2. 从索引池 Warehouse.groupsIndex 中获取 IRouteGroup 对应的实体类型(ARouter$$Group$$xxx.class)
                Class<? extends IRouteGroup> groupMeta = Warehouse.groupsIndex.get(postcard.getGroup());
                if (null == groupMeta) {
                    // ...异常日志
                } else {
                    try {
                        // 2.1 实例化 IRouteGroup(ARouter$$Group$$xxx.class)
                        IRouteGroup iGroupInstance = groupMeta.getConstructor().newInstance();
                        // 2.2 调用其 loadInto 方法, 将该 Group 下所有类的信息 RouteMeta 填充到 Warehouse.routes 中
                        iGroupInstance.loadInto(Warehouse.routes);
                        // 2.3 说明当前 group 下的 RouteMeta 已经解析到 Warehouse.routes 中了, 从集合中移除
                        Warehouse.groupsIndex.remove(postcard.getGroup());
                    } catch (Exception e) {
                        // ... 异常日志
                    }
                    // 2.4 重新调用 LogisticsCenter.completion, 下次将会走到 3 中
                    completion(postcard);   // Reload
                }
            } else {
                // 3. 给 postcard 注入数据
                postcard.setDestination(routeMeta.getDestination());
                postcard.setType(routeMeta.getType());
                postcard.setPriority(routeMeta.getPriority());
                postcard.setExtra(routeMeta.getExtra());
                // 3.1 获取 URI
                Uri rawUri = postcard.getUri();
                if (null != rawUri) {   // Try to set params into bundle.
                    // 3.2 分割 uri 参数
                    Map<String, String> resultMap = TextUtils.splitQueryParameters(rawUri);
                    // 3.3 获取参数类型并且注入 postcard 中
                    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()));
                        }
                        postcard.getExtras().putStringArray(ARouter.AUTO_INJECT, paramsType.keySet().toArray(new String[]{}));
                    }
                    // 3.5 mBundle 向 Bundle 中保存 URI键值对
                    postcard.withString(ARouter.RAW_URI, rawUri.toString());
                }
                // 4. 根据 routeMeta 的类型信息处理相应的操作
                switch (routeMeta.getType()) {
                    case PROVIDER:  // 4.1 为 ARouter 的 IProvider
                        // 4.1.1 构建实例对象
                        Class<? extends IProvider> providerMeta = (Class<? extends IProvider>) routeMeta.getDestination();
                        // 根据 IProvider 的信息从 providers 中获取缓存的实例对象
                        IProvider instance = Warehouse.providers.get(providerMeta);
                        if (null == instance) {
                            IProvider provider;
                            try {
                                // 反射创建实例对象
                                provider = providerMeta.getConstructor().newInstance();
                                provider.init(mContext);
                                // 添加到缓存池
                                Warehouse.providers.put(providerMeta, provider);
                                instance = provider;
                            } catch (Exception e) {
                                // ...
                            }
                        }
                        // 4.1.2 给 postcard 注入实例对象
                        postcard.setProvider(instance);
                        // 4.1.3 IProvider 类型的目标不允许设置为不可拦截(绿色通道)
                        postcard.greenChannel();
                        break;
                    case FRAGMENT :// 4.2 Fragment 的类型
                        // 4.2.1 FRAGMENT 类型的目标不允许设置为不可拦截(绿色通道)
                        postcard.greenChannel();
                    default:
                        break;
                }
            }
        }
    

    可见这个方法真的做了很多重要的事情

    • 从缓存池中 Warehouse.routes 获取对应的 ARouterGroupxxx.class 类的信息封装对象 routeMeta

    • routeMeta 在缓存中不存在

      • 从索引池 Warehouse.groupsIndex 中获取 IRouteGroup 对应的实体类型 IRouteGroup(ARouterGroupxxx.class)
      • 实例化 IRouteGroup(ARouterGroupxxx.class)
      • 调用其 loadInto 方法, 将该 Group 下所有类的信息 RouteMeta 填充到 Warehouse.routes 中
      • 说明当前 group 下的 RouteMeta 已经解析到 Warehouse.routes 中了, 从集合中移除
      • 重新回调 LogisticsCenter.completion 方法, 下次不会走此分支
    • routeMeta 在缓存中存在

      • 给 postcard 注入 routeMeta 中保存的数据
    • routeMeta 的类型信息处理相应的操作

      • PROVIDER:

        • 构建 IProvider 对象
        • 给 postcard 注入实例对象
        • 设置为绿色通道(不可拦截)
      • FRAGMENT:

        • 设置 为绿色通道, 其 实例 在上面分析过的 LogisticsCenter._navigation 中构建

    之后便可以通过 postcard.getProvider(); 返回 ARouter.navigation 的实例对象了

    三. 结语

    通过本次对 ARouter 进行分析, 借此厘清 ARouter 初始化的工作原理, 虽然说是初始化, 但可以发现很多核心代码都一并被分析了, 里面的缓存思想和代码设计是极好的, 非常值得学习, 笔者有很多分析不到位的地方, 希望大家能够批评指出, 接下来准备手写一份自己的 Router 库, 以加深对 Router 的理解, 到时候还希望大家的支持

    相关文章

      网友评论

        本文标题:ARouter 路由框架源码解析

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