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
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()方法
总结
- 单一的降级策略是针对某一次的页面跳转
- 全局的降级是针对项目只能够任何一次页面见的路由跳转
- 如果同时设置了单一和全局的,只会执行单一的全局的就会被覆盖
网友评论