ARouter源码简析系列二:navigation过程

ARouter源码简析系列一:初始化流程

之前讲了初始化流程,现在接着看navigation过程,先来一个使用示例 后面好举例

@Route(path = "/image/imageActivity")
class MainActivity : AppCompatActivity() {
    @Autowired(name = "tip")
    @JvmField
    var mTip: String? = ""
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        ARouter.getInstance().inject(this)
        setContentView(R.layout.layout_activity_main)
        findViewById<TextView>(R.id.mTvImageModule).setOnClickListener {
            ARouter.getInstance().build("/login/loginActivity").navigation(this)
        }
    }
}

1.postcard制作过程

postcard何许人也,翻译是明信片,也就是路由信息类,里面存着路由数据uri, 携带参数,路径等等

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;
        }

        // Set context to postcard.
        postcard.setContext(null == context ? mContext : context);

        try {
            LogisticsCenter.completion(postcard);
        } 
		//省略代码
        return null;
    }

postcard保存了所有跳转类相关信息
1.设置postcard的context
2.调用LogisticsCenter.completion完善postcard信息

2.完善postcard信息

2.1 @Route生成的映射类(方便举例说明)

public class ARouter$$Group$$image implements IRouteGroup {
  @Override
  public void loadInto(Map<String, RouteMeta> atlas) {
    atlas.put("/image/imageActivity", RouteMeta.build(RouteType.ACTIVITY, MainActivity.class, "/image/imageactivity", "image", new java.util.HashMap<String, Integer>(){{put("tip", 8); }}, -1, -2147483648));
  }
}

2.2 完善postcard过程 稍长 忍一下

  public synchronized static void completion(Postcard postcard) {
        if (null == postcard) {
            throw new NoRouteFoundException(TAG + "No postcard!");
        }
		//通过路由信息查找路由映射数据,第一次调用该分组下的路由的相关方法routeMeta一定是空,
		//因为映射表还没加载过该组下的任何路由信息,也就是2.1部分的loadInto还没调用过,没有
		//保存RouteMeta信息到集合中
        RouteMeta routeMeta = Warehouse.routes.get(postcard.getPath());
        
        if (null == routeMeta) {
        	//第一次调用目标路由走到这里
        	//查找分组表信息,在之前文章有介绍,初始化过程会加载分组信息
            if (!Warehouse.groupsIndex.containsKey(postcard.getGroup())) {
            //找不到分组抛出异常
                throw new NoRouteFoundException(TAG + "There is no route match the path [" + postcard.getPath() + "], in group [" + postcard.getGroup() + "]");
            } else {
            	//找到分组
                try {
                  	//省略代码
                  	//这一步,将调用目标组下的ARouter\$Group\$XX类文件,也就是2.1的代码
                  	//将路径映射的类加载到WareHouse的集合中,
                  	//下面有贴出代码addRouteGroupDynamic的实现过程
                    addRouteGroupDynamic(postcard.getGroup(), null);

             		//省略代码
                } catch (Exception e) {
                    throw new HandlerException(TAG + "Fatal exception when loading group meta. [" + e.getMessage() + "]");
                }
				//再次调用自己,这一次因为将数据加载到集合中了,
				//所以这次就会走到下面的else分支
                completion(postcard);   // Reload
            } else {
            //填充postcard数据
            postcard.setDestination(routeMeta.getDestination());
            postcard.setType(routeMeta.getType());
            postcard.setPriority(routeMeta.getPriority());
            postcard.setExtra(routeMeta.getExtra());

           	//省略uri处理过程

			//Provider和Fragment设置为greenChannel(绿色通道会跳过拦截器处理过程)
            switch (routeMeta.getType()) {
            //如果是Provider类型 也就是我们定义的IProvider对象
                case PROVIDER:  
      				//从集合中查找对象,有就取出实例对象
                    Class<? extends IProvider> providerMeta = (Class<? extends IProvider>) routeMeta.getDestination();
                    IProvider instance = Warehouse.providers.get(providerMeta);
                    if (null == instance) { 
                    	//不存在 反射创建对象,保存到Warehouse统一管理
                        IProvider provider;
                        try {
                            provider = providerMeta.getConstructor().newInstance();
                            provider.init(mContext);
                            Warehouse.providers.put(providerMeta, provider);
                            instance = provider;
                        } catch (Exception e) {
                            logger.error(TAG, "Init provider failed!", e);
                            throw new HandlerException("Init provider failed!");
                        }
                    }
                    //添加到postcard
                    postcard.setProvider(instance);
                    postcard.greenChannel();    // Provider should skip all of interceptors
                    break;
                case FRAGMENT:
                    postcard.greenChannel();    // Fragment needn't interceptors
                default:
                    break;
            }
        }
        } 
    }

public synchronized static void addRouteGroupDynamic(String groupName, IRouteGroup group) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        if (Warehouse.groupsIndex.containsKey(groupName)){
         //找到相关组,调用这个组映射的类,也就是上面贴出来的2.1部分@Route生成的类
         //调用该类的loadInto将路由映射数据添加到集合中保存
         Warehouse.groupsIndex.get(groupName).getConstructor().newInstance().loadInto(Warehouse.routes);
            //loadInto调用过了 就不需要保留分组表中该分组信息了,移除掉,省点内存
            Warehouse.groupsIndex.remove(groupName);
        }

        // cover old group.
        if (null != group) {
            group.loadInto(Warehouse.routes);
        }
    }

3.导航处理流程

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;
        }

        //添加context信息到postcard
        postcard.setContext(null == context ? mContext : context);

        try {
        	//前面介绍的完善postcard过程 不必多说了
            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();
                    }
                });
            }
			//回调通知onLost()
            if (null != callback) {
                callback.onLost(postcard);
            } else {
                // 全局的降级处理服务,在这里可以做toast提示错误之类
                DegradeService degradeService = ARouter.getInstance().navigation(DegradeService.class);
                if (null != degradeService) {
                    degradeService.onLost(context, postcard);
                }
            }

            return null;
        }
		
		//这里回调找到目标的通知
        if (null != callback) {
            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
                 *
                 * @param postcard route meta
                 */
                @Override
                public void onContinue(Postcard postcard) {
                    _navigation(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 {
        	//具体的导航处理
            return _navigation(postcard, requestCode, callback);
        }

        return null;
    }

4.不同类型路由匹配处理流程

private Object _navigation(final Postcard postcard, final int requestCode, final NavigationCallback callback) {
        final Context currentContext = postcard.getContext();
		//根据类型 处理不同
        switch (postcard.getType()) {
            case ACTIVITY:
                //Activity跳转  通过Intent跳到目标Activity
                //看下前面@Route生成的类, 保存的有class对象
                final Intent intent = new Intent(currentContext, postcard.getDestination());
                //参数传递
                intent.putExtras(postcard.getExtras());

                // 设置Flags  比如启动模式之类
                int flags = postcard.getFlags();
                if (0 != flags) {
                    intent.setFlags(flags);
                }

                // 如果context不是Activity,需要加上NEW_TASK,
                //因为Application和Service没有Activity栈
                if (!(currentContext instanceof Activity)) {
                    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                }

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

                // Navigation in main looper.
                runInMainThread(new Runnable() {
                    @Override
                    public void run() {
                    //启动Activity
                        startActivity(requestCode, currentContext, intent, postcard, callback);
                    }
                });

                break;
            case PROVIDER:
            	//如果是Provider,返回之前填充到postcard保存的IProvider对象,
            	//这样调用者就可以调用IProvider定义的方法
                return postcard.getProvider();
            case BOARDCAST:
            case CONTENT_PROVIDER:
            case FRAGMENT:
            	//fragment的处理也是通过反射创建对象
                Class<?> fragmentMeta = postcard.getDestination();
                try {
                    Object instance = fragmentMeta.getConstructor().newInstance();
                    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;
    }

总结

navigation的调用流程就结束了,原理还是比较简单,代码过程也比较线性,容易理解,如有疑问,欢迎提出

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值