美文网首页
ARouter源码分析-页面跳转

ARouter源码分析-页面跳转

作者: dashingqi | 来源:发表于2020-07-20 23:12 被阅读0次
    Android_Banner.jpg

    简介

    • ARouter我们通常用在组件化中,在不同模块间进行跳转
    • 通常的实现步骤就是
      • 在目标页面使用@Route(path = "/test/activity")注解,声明一个路由地址
      • 在跳转的时候我们使用ARouter.getInstance().build("/test/activity").navigation()
    • 以上就是我们简单的页面跳转,而我们的分析也就按照上面的代码进行分析

    页面跳转分析

    ARouter.getInstance().build("").navigation()
    
    • 我们把上面的代码拆分成三部分作出分析
      • ARouter.getInstance()
      • ARouter # build()
      • Postcard # navigation()
    ARouter # getInstance()
    • 在初始化的时候分析过,该方法的调用就是通过单利模式(双重检查模式)拿到ARouter的实例
    • 这里就不做过多解释了
    ARouter # build
        // 传入一个路由地址,调用了_ARouter # build()
        public Postcard build(String path) {
            return _ARouter.getInstance().build(path);
        }
    
    _ARouter # build()
     protected Postcard build(String path) {
     // 首先校验路由地址
            if (TextUtils.isEmpty(path)) {
                throw new HandlerException(Consts.TAG + "Parameter is invalid!");
            } else {
            // 路由地址校验成功后,根据IoC的ByType方式获取到PathReplaceService的实现子类
                PathReplaceService pService = ARouter.getInstance().navigation(PathReplaceService.class);
                if (null != pService) {
                    path = pService.forString(path);
                }
                // 调用了内部build()
                // 其中 path 是路由的全地址名称 ----> "/test/activity"
                // extractGroup() 返回的是路由地址中的一级地址 ("/test/activity")也就是 test
                return build(path, extractGroup(path), true);
            }
        }
        
        // 我们接着看下 build(path, extractGroup(path), true);
     
        
        //该方法返回了一个Postcard对象
        protected Postcard build(String path, String group, Boolean afterReplace) {   
        // 校验 路由全地址和一级地址
            if (TextUtils.isEmpty(path) || TextUtils.isEmpty(group)) {
                throw new HandlerException(Consts.TAG + "Parameter is invalid!");
            } else {
            // afterReplase == true
                if (!afterReplace) {
                    PathReplaceService pService = ARouter.getInstance().navigation(PathReplaceService.class);
                    if (null != pService) {
                        path = pService.forString(path);
                    }
                }
                //返回一个Postcard对象携带path和group,
                return new Postcard(path, group);
            }
        }
    
    • 总结
      • ARouter# build() 返回的是一个Postcard对象
      • 当前返回的Postcard对象携带 path和group两个路由地址数据
      • ARouter中全权代理给了_ARouter类来执行

    Postcard # navigation()

        public Object navigation() {
            return navigation(null);
        }
    
        public Object navigation(Context context) {
            return navigation(context, null);
        }
    
        // 调用到此重载方法
        // context == null ,callback == null
        public Object navigation(Context context, NavigationCallback callback) {
            return ARouter.getInstance().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()
        
    
    _ARouter # navigation()
    protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
            PretreatmentService pretreatmentService = ARouter.getInstance().navigation(PretreatmentService.class);
            if (null != pretreatmentService && !pretreatmentService.onPretreatment(context, postcard)) {
                // Pretreatment failed, navigation canceled.
                return null;
            }
    
            try {
            // ---------> 分析1:
                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) {
                    callback.onLost(postcard);
                } else {
                    // No callback for this invoke, then we use the global degrade service.
                    DegradeService degradeService = ARouter.getInstance().navigation(DegradeService.class);
                    if (null != degradeService) {
                        degradeService.onLost(context, postcard);
                    }
                }
    
                return null;
            }
    
            if (null != callback) {
                callback.onFound(postcard);
            }
    
            //针对Fragment或者Provider类型的 不会走拦截器的逻辑
            // 默认不是绿色通道
            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) {
                    // ---------> 分析2:
                        _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());
                    }
                });
            } else {
                //--------> 分析2:直接进行跳转了
                return _navigation(context, postcard, requestCode, callback);
            }
    
            return null;
        }
    
    分析1:LogisticsCenter.completion(postcard);
    • 调用该方法的作用就是补充一下Postcard携带的数据
     public synchronized static void completion(Postcard postcard) {
            //校验 postcard
            if (null == postcard) {
                throw new NoRouteFoundException(TAG + "No postcard!");
            }
            
            // postcard.getPath() ----> "/test/activity"
            // 从仓库的路由地址清单列表中拿到对应的RouteMeta
            RouteMeta routeMeta = Warehouse.routes.get(postcard.getPath());
            // 如果获取到的为null,说明当前路由地址清单没有被加载
            if (null == routeMeta) {    
                // 根据一级地址,拿到对应的路由地址清单的文件类(ARouter$$Root$$工程名)
                Class<? extends IRouteGroup> groupMeta = Warehouse.groupsIndex.get(postcard.getGroup());  // Load route meta.
                // 如果获取到的当前路由地址清单文件类不存在。就抛出一个异常
                if (null == groupMeta) {
                    throw new NoRouteFoundException(TAG + "There is no route match the path [" + postcard.getPath() + "], in group [" + postcard.getGroup() + "]");
                } else {
                    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();
                        // 调用loadInto(),传入Warehouse.routes,装载路由地址清单数据
                        iGroupInstance.loadInto(Warehouse.routes);
                        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);   // Reload
                }
            } else {
            // 当从路由地址清单文件中找到当前路由地址对应的RouteMeta,就进行Postcard的数据填充。
                // routeMeta.getDestination() ------> 获取到的是 目标类的 Class对象
                postcard.setDestination(routeMeta.getDestination());
                // routeMeta.getType() ---> 目标类的类别 (Activity ,Fragment,Provider,Interceptor)
                postcard.setType(routeMeta.getType());
                //当前的优先级
                postcard.setPriority(routeMeta.getPriority());
                //携带的数据Bundle
                postcard.setExtra(routeMeta.getExtra());
    
                Uri rawUri = postcard.getUri();
                if (null != rawUri) {   // Try to set params into 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()) {
                    // 是provider类型的目标类必须实现IProvider的接口
                    case PROVIDER:  
                        
                        //获取provider目标类的Class对象
                        Class<? extends IProvider> providerMeta = (Class<? extends IProvider>) 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;
                }
            }
        }
    
    分析2 _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()) {
                //如果是ACTIVITY类型
                case ACTIVITY:
                    // Build intent
                    // postcard.getDestination() ---> 获取到的是目标类
                    //进行Intent的拼装
                    final Intent intent = new Intent(currentContext, postcard.getDestination());
                    intent.putExtras(postcard.getExtras());
    
                    // 设置falg信息
                    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);
                    }
    
                    // 设置Action的信息
                    String action = postcard.getAction();
                    if (!TextUtils.isEmpty(action)) {
                        intent.setAction(action);
                    }
    
                    // 
                    runInMainThread(new Runnable() {
                        @Override
                        public void run() {
                        //切换到UI线程中
                        // 为什么切换到UI线程中呢?
                        // 因为正常的页面跳转 在跳转钱都会执行拦截器的操作,为拦截器的执行是在线程池中
                        // 对应的回调也运行在工作线程中
                        // 调用startActivity()方法,发起页面跳转的请求
                            startActivity(requestCode, currentContext, intent, postcard, callback);
                        }
                    });
    
                    break;
                case PROVIDER:
                // 是provider类型,就返回Provider实现子类的对象
                    return postcard.getProvider();
                case BOARDCAST:
                case CONTENT_PROVIDER:
                case FRAGMENT:
                    Class fragmentMeta = postcard.getDestination();
                    try {
                        Object instance = fragmentMeta.getConstructor().newInstance();
                        //如果手Fragment类型
                        // 把要传递到Fragment中的数据 设置给当前的Fragmenrt
                        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;
        }
    

    总结

    对于普通的页面跳转,原理还是很简单的,其中涉及到几个重要的类 ARouter ,_ARouter,Postcard extends RouteMeta,LogisticsCenter,Warehouse

    • 对于 ARouter和 _ARouter:_ARouter就是ARouter的代理类,所有的操作都是在_ARouter中
    • Postcard:是用来页面跳转进行数据传递的作用
    • RouteMeta:一般用于在编译期间在生成路由地址清单文件时与路由地址形成映射关系的
    • LogisticsCenter:数据运送中心吧,主要提供操纵Postcard 比如completate()方法
    • Warehouse:数据仓库,用于存储很多映射关系,包括组的(一级路径),路由地址清单,Provider类型,拦截器类型
    • 看下在编译期间生成的 ARouter_Route_工程名 文件
    public class ARouter$$Root$$modulearouter implements IRouteRoot {
      @Override
      public void loadInto(Map<String, Class<? extends IRouteGroup>> routes) {
        routes.put("interceptor", ARouter$$Group$$interceptor.class);
      }
    }
    
    • 看下生成的 ARouter_Group_工程名
    public class ARouter$$Group$$interceptor implements IRouteGroup {
      @Override
      public void loadInto(Map<String, RouteMeta> atlas) {
        atlas.put("/interceptor/test", RouteMeta.build(RouteType.ACTIVITY, InterceptorTestActivity.class, "/interceptor/test", "interceptor", null, -1, -2147483648));
      }
    }
    
    

    相关文章

      网友评论

          本文标题:ARouter源码分析-页面跳转

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