-
Notifications
You must be signed in to change notification settings - Fork 208
ProxyIntent
因为 URL
获取 Intent
和发起一个跳转的本质差不多, 只不过前者是拿到 Intent
不使用罢了. 但是假如你得拦截器有作一些耗时得操作、或者阻塞得去跳转界面拿数据. 那你此操作就和触发一次真实的跳转的没啥区别了?这是绝对不行的. 所以不会让用户能拿到 真正目标界面的 Intent
.
而有些框架很有趣, 能跳转所有拦截器直接拿到 URL
对应的 Activity 的 Intent
, 比如 ARouter
就可以, 有些人就觉得人家为啥可以, 你怎么不可以?这问题很有趣, 你觉得人家提供了 Api
解决了你的问题, 但是这真的正确吗?你要知道拦截器本质上是干嘛的?拦截器所有的请求,做一些全局或者部分 URL
匹配才会做的事情. 拦截器针对的目标是全部的 URL
. 并且拦截器拥有改变请求的的能力. 你怎么知道经过若干拦截器修改后的请求就是你想象的目标 Activity
. 比如 URL
为 "Router://user/test?type=1", 有一个拦截器是根据请求的参数跳转到不同的界面。这时候发起正常跳转是可能对应两个 Activity
, 那么问题来了 "Router://user/test" 你觉得它对应哪个 Activity
? 所以总结如下:
-
URL
是一定要经过拦截器的, 否则拦截器的作用将大打折扣, 也可平常理解的拦截器概念有违背- 用户可能在拦截器中执行耗时操作
- 用户可能在拦截器中跳转到一个其他界面去拿到数据, 再接下去流程(比如登录拦截器, 就是帮助没有登录的实现登录, 再继续流程)
-
URL
的真实跳转的目标可能是不确定的
基于上述总结的两点, 不到发起 Intent
跳转这句代码之前, 你是不可能拿到真正的 Intent
的
你想不发起跳转拿到 Intent
, 下面两点是相互矛盾的.
- 不经过拦截器你根本不知道你的请求是否会被更改.
- 但是经过拦截器又可能跳出中间界面真正的执行了一些代码. 比如日志、记录、数据库操作、登录拦截器 等等
有些时候, 正如一位使用者提的 issue 所说的一样, 总有一些时候你是需要拿到 Intent
交给系统的, 比如小部件、通知等等.
跳转的这部分不能像自己平常跳转一样使用 Router.with(context).host("xxx").path("xxx").forward();
所以设计 ProxyIntent
的目的就是为了解决这个问题. 您可以拿到一个 Intent
, 并且这个 Intent
交给系统跳转后还能最终无感的跳转到真正的目标界面
我们知道, 一般情况下, 我们使用组件化框架的路由功能都是达到了一个目的:
- 真正的
Intent
被一个URL
所代替, 你可以理解为你访问不到真正的Intent
, 只能通过URL
去访问.URL
可以看做是真正的Intent
的一个别名. 系统会解析URL
到真正的Intent
的.
在我们 Android
中, 其实一个 Activity
的跳转其实就是一个 Intent
, 只不过这个 Intent
的意图就是指向了 Activity
, 整理上述所说的. 我们可以认为. URL
--> Intent
--> Activity
我们全程都应该直接和 URL
打交道, 而不应该绕过 URL
去拿到 Intent
或者目标的 Activity
.
这时候 ProxyIntent
的作用就体现出来了. 首先. ProxyIntent
本质上是一个 Intent
, 你可以通过以下方式构建出一个 ProxyIntent
Intent intent = Router.newProxyIntentBuilder()
.host("user")
.path("personCenter")
// 可省略, 省略后默认使用框架自带的无界面的 Activity
.proxyActivity(this.getClass())
.buildProxyIntent();
构建出来的 Intent
就是一个 ProxyIntent
, 它有两部分组成:
- 这个
ProxyIntent
的意图的目标是一个代理的Activity
. 如上面代码所示, 这个代理Activity
可以自定义. - 这个
ProxyIntent
中有 跳转到真正的目标界面所需的所有的参数和数据.
当你拿到一个 ProxyIntent
, 假设你创建了一个通知栏消息, 点击消息的触发的 Intent
就是刚刚你拿到的 ProxyIntent
. 那么流程如下:
-
点击消息 --> 跳转到代理
Activity
-
代理
Activity
解析参数拿到真正的目标界面的URL
和所需的其他数据(Bundle、flags、categories....) -
代理
Activity
根据上一步拿到的URL
和所需数据发起跳转. -
真正的目标界面被正确的打开
其中的代理 Activity
可以是框架默认的也可以是自定义的. 如果是自定义的. 还请在 onCreate
方法和 onNewIntent()
方法中添加如下的代码:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// ......
startProxyRouter(getIntent().getExtras());
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
startProxyRouter(intent.getExtras());
}
private void startProxyRouter(@Nullable Bundle bundle) {
if (Router.haveProxyIntent(bundle)) {
Router.with(this)
.proxyBundle(bundle)
.forward();
}
}
并且你得关注你自定义的代理 Activity
的启动模式. 比如消息的触发, 代理 Activity
存在或者不存在的时候都可能触发. 我这边建议使用 singleInstance
.
具体的代码可以查看 Component
项目的源码中的示例模块 app
中的 MainAct
界面. 有两个按钮可以分别生成两个通知. 一个使用默认的代理 Activity
, 一个使用 MainAct
为代理 Activity
. 无论程序是否运行, 点击通知两者都可完成跳转.