Observable
的问题Action
本质是一个全局的系统回调,主要用于预埋的一系列操作,例如:弹窗、上传日志、清理缓存。
当用户执行某些操作(打开某个页面、H5点击某个按钮、动态页面配置的点击事件)时,将会自动触发,执行预埋的 Action 逻辑。
在Android上,有很多能力可以实现类似的功能,比如广播
、EventBus
、Flow
、LiveData
等等实现观察者模式的框架。但是全都有个严重的问题:通知是不可追溯的,也就是通常说的消息泛滥。当消息多了以后,你很难知道哪个消息是在哪里发出的,有哪些地方接收了这个消息。
与 Android 系统自带的广播通知类似,你可以在任何地方声明动作与处理方式。只不过在 TheRouter 内,所有Action
都是可以被跟踪的,只要你愿意,可以在日志中将所有的动作调用栈输出,以方便调试使用。在开发期,可以直接通过 IDE
插件,在消息的发出和接收位置直接跳转。
声明一个 Action:
// action建议遵循一定的格式
const val ACTION = "therouter://action/xxx"
@FlowTask(taskName="action_demo")
fun init(context: Context) =
TheRouter.addActionInterceptor(ACTION, object: ActionInterceptor() {
override fun handle(context: Context, args: Bundle): Boolean {
// do something
return false
}
})
从 1.1.3-rc1
开始,Action 也支持注解声明,可使用如下方式声明:
@ActionInterceptor(actionName = "action_demo")
public class TestActionInterceptor extends ActionInterceptor {
@Override
public boolean handle(@NonNull Context context, @NonNull Navigator navigator) {
Toast.makeText(context, HomePathIndex.ACTION2, Toast.LENGTH_SHORT).show();
// true表示阻断(消费掉),false表示继续传递,一般都用false
return super.handle(context, navigator);
}
}
执行一个 Action:
// action建议遵循一定的格式
const val ACTION = "therouter://action/xxx"
// 如果执行了一个没有被声明的Action,则不会有任何动作
TheRouter.build(ACTION).action()
每个Action
允许关联多个 ActionInterceptor
进行处理,多个ActionInterceptor
之间可以自定义拦截器优先级,同时允许终止接下来的低优先级拦截器的执行。
最典型应用场景:首页可能会有多个弹窗,不同业务之间的弹窗是有优先级之分的,为了体验优化我们肯定不会在首页一次把所有弹窗全部弹出,可以通过ActionInterceptor
为每个弹窗声明好优先级关系,假设需求是首页只能弹出3个弹窗,那么第三个弹窗处理完毕即可关闭当前事件,接下来的拦截器将不会被响应。
abstract class ActionInterceptor {
abstract fun handle(context: Context, args: Bundle): Boolean
fun onFinish() {}
/**
* 数字越大,优先级越高
*/
open val priority: Int
get() = 5
}