美文网首页
ARouter源码分析-降级策略

ARouter源码分析-降级策略

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

    简介

    • 通常我们进行页面跳转的时候,调用startActivity()之后我们就无法控制了,之后出现什么问题或者异常,我们都把控不好,有时候针对用户来说就是一个闪退,这样用户体验很不好
    • 但是ARouter给我们提供的这个降级策略,便能很友好的避免这个问题,当进行页面跳转出现问题的时候,我们可以通过降级策略去加载一个H5页面或者跳转到一个提醒页面,这样对用户来说体验就非常好了

    降级策略的使用

    • ARouter中为我们提供了单独降级和全局降级
    • 这两种降级不能同时使用,如果同时使用那么单独降级会将全局降级进行覆盖了,不会执行全局降级的逻辑了
    单独降级 --- 接口
    • 测试代码
     mBtnDegrade.setOnClickListener(view->{
                ARouter.getInstance().build("/test/test").navigation(this, new NavigationCallback() {
                    @Override
                    public void onFound(Postcard postcard) {
                        Log.d(TAG, "onFound: 找到了");
    
                    }
    
                    /**
                     * 出现问题会回调该方法
                     * 也就是我们降级策略的处理回调
                     * @param postcard
                     */
                    @Override
                    public void onLost(Postcard postcard) {
                        Log.d(TAG, "onLost: 没有找到哟");
    
                    }
    
                    @Override
                    public void onArrival(Postcard postcard) {
                        Log.d(TAG, "onArrival: 跳转完事了");
    
                    }
    
                    @Override
                    public void onInterrupt(Postcard postcard) {
                        Log.d(TAG, "onInterrupt: 被拦截了");
    
                    }
                });
    
            });
    // 在本例子中,我们的路由地址 ("/test/test")是一个不存在的页面,
    // 观察打印的log我们可以看出来回调到了 onLost方法
    // 这就是单独降级策略达到的效果,我们可以在 onLost方法中做一些逻辑
    //说完了单独降级我们看下全局降级吧
    
    全局降级 --- 服务接口的形式(Provider)
    • 全局降级就是我们需要实现ARouter提供的DegradeService接口(DegradeServie extends IProvider)是Provider类型的
    • DegradeService接口内就只有一个方法 onLost() 如果在页面跳转出现任何问题,都会回调到onLost方法中
    • 代码测试
    // 声明一个降级策略服务类 实现了 DegradeService
    // 使用注解Route 标识这个 Provider类型
    @Route(path = "/degrade/test")
    public class MyDegradeService implements DegradeService {
    
        private static final String TAG = "MyDegradeService";
        @Override
        public void onLost(Context context, Postcard postcard) {
            Log.d(TAG, "onLost: ");
    
        }
    
        @Override
        public void init(Context context) {
            Log.d(TAG, "init: ");
    
        }
    }
    
    //点击按钮进行页面跳转(提供的路由地址不存在)
     mBtnGlobalDegrade = findViewById(R.id.btnGlobalDegrade);
            mBtnGlobalDegrade.setOnClickListener(view ->{
                ARouter.getInstance().build("/test1/test1").navigation();
            });
    // 参看log 显示如下
    2020-07-09 00:04:21.032 4133-4133/com.dashingqi.module.arouter D/MyDegradeService: init: 
    2020-07-09 00:04:21.033 4133-4133/com.dashingqi.module.arouter D/MyDegradeService: onLost: 
    
    // 这是全局的降级策略,我们任何页面跳转出现问题 都会回调到自定义DegradeService服务类中的onLost方法中
    
    

    降级策略的过程分析

    单一降级(接口)
    • 单一跳转的降级策略是在navigation()方法中 传入了一个context和一个NavigationCallback接口,我们跟下这个navigation()方法
    // ARouter.getInstance().build("") ----> Postcard
    // Postcard # navigation()
    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 {
                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);
            }
    
            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(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 {
                return _navigation(context, postcard, requestCode, callback);
            }
    
            return null;
        }
    
    • 是不是感觉很熟悉,这不就是在页面跳转时最终执行的地方嘛。
      • 首先做了Postcard的数据补充
      • 判断是不是绿色通道,决定了要不要执行拦截器操作
      • 最后没出现问题的话都会执行到 _navigation()
    • 正如上述所说,正常执行会执行_navigation(),那么我们看下针对异常情况是怎么处理的
      • 可以看到 我们抓了NoRouteFoundException 异常
      • 在 LogisticsCenter # completion() 方法中 如果在数据仓库中没有找到对应路由地址我们就会抛出NoRouteFoundException
      • 看下是如何处理的这个异常
        • 可以很明显看到 在catch快中,如果callback不为null,就回调了onLost()方法,这个callback就是在navigation()方法中传入的
    • 到此单一降级策略就破案了
    全局的降级策略
    • 同样全局的降级策略也是发生在LogisticsCenter#completion()方法中
    • 列下关键代码
    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);
                    }
                }
    // 很好理解,可以看出如果同一个页面跳转,分别设置了单一降级策略和全局降级策略,仅仅会执行单一的降级策略不会执行全局的降级策略。
    // 针对是全局降级策略,首先更具IoC中的ByType()方法拿到对应的服务实例(实则就是我们自定义的全局降级策略类)
    // 当发现我们自定义的的全局降级策略类,就会回调执行它的onLost()方法
    

    总结

    • 单一的降级策略是针对某一次的页面跳转
    • 全局的降级是针对项目只能够任何一次页面见的路由跳转
    • 如果同时设置了单一和全局的,只会执行单一的全局的就会被覆盖

    相关文章

      网友评论

          本文标题:ARouter源码分析-降级策略

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