-
Notifications
You must be signed in to change notification settings - Fork 208
ProxyIntent
有些时候, 正如一位使用者提的 issue 所说的一样, 总有一些时候你是需要拿到 Intent
交给系统的, 比如小部件、通知等等.
跳转的这部分不能像自己平常跳转一样使用 Router.with(context).host("xxx").path("xxx").forward();
所以设计 ProxyIntent
的目的就是为了解决这个问题. 您可以拿到一个 Intent
, 并且这个 Intent
交给系统跳转后还能最终无感的跳转到真正的目标界面
ProxyIntent
有两部分组成
- 跳转的目标是
Proxy Activity
-
Intent
中有真实的目标所有信息URL
Bundle
flags
categories
- ......
路由的本质是用一个 URL
去表示一个可路由的目标 Activity Intent
, 但是两者的对应关系并不是确定的. 这是啥意思呢?比如 "Router://user/test?type=1" 这个 URL
, 它可能会途径若干个拦截器, 如果有拦截器对 URL
进行修改, 那么路由的目标也就随之改变了. 所以一个 URL
需要经过了所有的拦截器, 直到 startActivity
之前才知道目标是哪个的.
反之, 我们更加不知道一个 Activity Intent
对应哪个 URL
的. 所以在我们的路由框架中, 你是没法提前不发生跳转获取到一个目标的 Intent
的.
这时会有人说了, 那就让 URL
经过正常跳转的所有流程, 最终不执行 startActivity
不就完了. 这不就拿到了目标 Intent
了吗.
上面这问题思路是对的, 但是我们不能这么做, 原因有以下几点:
- 如果真的经过所有拦截器, 和真正的跳转就差
startActivity
方法的调用. 那么你可能会产生脏数据或者莫名的界面跳转. 比如有些拦截器是记录日志、拦截器中实现登录、数据库操作 等等 - 当你使用路由框架的那一刻起, 其实你应该有一个思想上的转变, 那就是
描述
一个可路由的目标再也不是以前原生的Intent
了, 而是一个URL
, 这个URL
. 你再也不应该直接接触Intent
了. 下面我写了两个层面的对应关系-
URL
对应Component
框架的跳转方式 -
Intent
对应Android
系统的跳转方式
-
- 所以当你组件化框架, 你如果需要提前拿到一个目标的
Intent
, 那这个Intent
的目标不应该是真正的目标, 而是一个叫做代理界面的目标. 代理界面是一个Activity
, 它可以接受你的Intent
传递过来的信息拿到你要跳转的URL
, 然后它会帮你发起跳转
所以在 Component
中你拿到一个 Proxy Intent
, 此 Intent
你在任何地方使用, 最终的流程如下:
Proxy Intent --> ProxyActivity --> 获取目标的信息 --> 通过 Router 发起跳转 --> 到达真正的目标
你可以通过以下方式构建出一个 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
. 无论程序是否运行, 点击通知两者都可完成跳转.
- 因为
URL
在跳转的时候会经过若干拦截器, 不知道会被修改成什么样, 自然无法知道最终的URL
是什么样的. 所以也无法知道最终对应的Intent
是哪个 - 不真正发生跳转的时候, 我们如果让
URL
经过所有拦截器, 最终获取到真正的目标的Intent
, 思路是对的, 但是拦截器的作用是非常强大的, 他可以做任何事情. 所以你如果不是真的跳转, 但是执行了所有拦截器. 会有下面几个问题- 脏数据的产生, 比如拦截器有日志、记录等功能
- 拦截器可能实现类似登录的效果, 会让本次路由登陆成功之后才放过本次拦截, 那你利用
URL
获取Intent
岂不是会莫名有界面的跳转发生?明显不对
- 思想的问题, 大家使用了路由框架之后, 对于目标界面的理解还是
Intent
. 这是系统对一个目标的封装. 但是对于路由框架, 一个RouteRequest
对象才是. 里面最关键的就是URL
属性, 所以当你使用了路由框架, 你应该都使用URL
或者RouteRequest
来表示一个目标才对