参考文献:
superxlcr 的 ARouter 学习笔记 http://blog.csdn.net/superxlcr/article/details/77966142
码字农民工的文章 http://www.jianshu.com/p/11d028ae872d
繁华落尽 666 的文章 http://blog.csdn.net/vv765947965/article/details/70745341
本文主要介绍的知识点
关于 android 路由框架解决的问题
android 路由框架的使用(这里只是介绍 ARouter 的使用)
关于使用 ARouter 框架的注意事项
总结
1.Android 路由框架解决的问题
相信大家在工作中都会遇到这样的问题, 通过其他 App 或者通过网页跳转到指定的自己的 App 或者跳转到指定的页面中去, 一般都是在推送中或者通过 Banner 点击之后的操作, 一般的操作都是像下面这样的
设置相应的 intent-filter
<intent-filter>
<action android:name="com.hejin.arouter.Main2Activity"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
复制代码
通过 Intent 隐式跳转到相应的 Activity
- Intent intent = new Intent();
- intent.setAction("com.hejin.arouter.Main2Activity");
- startActivity(intent);
复制代码
其实这里我要说明一下, 如果你是正规的开发公司我觉得一般都不会这么去写, 其实这个跳转完全能实现, 但是一般正规的公司都会定一些协议和端口号, 也就是说会添加 scheme 来指定一些数据的协议部分和 path 进行匹配, 但是随着时间的推移和团队的扩大, 会慢慢的暴露出很多问题:
集中式的 URL 管理: 谈到集中式的管理, 总是比较蛋疼, 多人协同开发的时候, 大家都去 AndroidManifest.xml 中定义各种 IntentFilter, 使用隐式 Intent, 最终发现 AndroidManifest.xml 中充斥着各种 Schame, 各种 Path, 需要经常解决 Path 重叠覆盖, 过多的 Activity 被导出, 引发安全风险等问题
可配置性较差: Manifest 限制于 xml 格式, 书写麻烦, 配置复杂, 可以自定义的东西也较少
跨模块无法显式依赖: 在 App 小有规模的时候, 我们会对 App 做水平拆分, 按照业务拆分成多个子模块, 之间完全解耦, 通过打包流程控制 App 功能, 这样方便应对大团队多人协作, 互相逻辑不干扰, 这时候只能依赖隐式 Intent 跳转, 书写麻烦, 成功与否难以控制.
尤其是在项目演进的时候都会进行组件化开发, 所以这里网上有很多大神就研究出路由框架这么一个东西, 解决了上面的相应问题, 这里接触的就是阿里巴巴开源的 ARouter 在 GitHub 上已经已经有 3.+k 的 start 了, 相对来说应该比较稳定, 所以让我们开始吧!
2.ARouter 的简单使用
2.1 首先是把 ARouter 引入到项目中去
首先在在 module 中配置相应的参数
- defaultConfig {
- .......
- javaCompileOptions {
- annotationProcessorOptions {
- arguments = [ moduleName : project.getName() ]
- }
- }
- }
复制代码
然后配置 api 和 compiler(这个也是在 module 中)
- dependencies {
- compile 'com.alibaba:arouter-api:x.x.x'
- annotationProcessor 'com.alibaba:arouter-compiler:x.x.x'
- ...
- }
复制代码
上面是 github 上面写的内容, 但是有一点他没有写, 但是就是一定要在项目的 gradle 中添加下面这段代码:
- dependencies {
- classpath 'com.android.tools.build:gradle:2.3.3'
- classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' // 路由需要
- // NOTE: Do not place your application dependencies here; they belong
- // in the individual module build.gradle files
- }
复制代码
这句话一定要加上否则根本就跳转不过去, 具体为什么我还真是不知道.... 有了以上的内容就完成了基本的配置, 就可以进行相应的跳转了...
2.2 代码中的简单使用
在 Application 中初始化 ARouter
- /* 初始化路由框架 */
- ARouter.init(this);
复制代码
首先要在你要跳转的 Activity(或者说是目标的 Activity)添加注释
@Route(path = "XXX/XXX")
复制代码
这里面要注意两点首先这个注解里面的内容必须是二级菜单, 这个在 github 上面有解释, 其次就是这个注解要写在 Activity 的类上边
通过代码进行跳转(发起路由)
- ARouter.getInstance().build("/XXX/XXX").navigation();
- // 跳转中携带参数
- ARouter.getInstance().build("/XXX/XXX")
- .withLong("key", "value")
- .withString("key", "value")
- .navigation
复制代码
这里面的参数要和你要跳转的 Activity 注解中的参数保持一致, 当你传递参数的时候, 你直接通过 Intent 去取就可以了.
通过以上步骤就能实现基本的跳转传递参数了, 但是身为有逼格的程序员我们怎么能这样就满足了呢?
3.ARouter 进阶使用
3.1 利用 Uri 进行跳转
- Uri uri = Uri.parse("/test/activity");
- ARouter.getInstance()
- .build(uri)
- .navigation();
复制代码
3.2 传递参数的获取问题
当你传递参数的时候你可以通过 Intent 取获取, 当然也可以通过相应的注解进行获取, 就像下面这样:
- @Autowired(name = "xxx")
- public String text;
复制代码
这里呢要注意, 修饰符必须是 public 并且 key 值要相互对应. 还要在目标的 Activtiy 中添加 **ARouter.getInstance().inject(this);** 才可以使用相应的值, 否则取值的时候会失败, 但是不会报空指针.
3.3 关于转场动画的跳转处理
有没有想过, 之前在 Activity 跳转的时候可以使用 overridePendingTransition();, 但是现在通过路由跳转的话, 没有地方取设置动画了, 然后 ARouter 为我们想到了这个问题.
旧动画: 使用 withTransition 方法即可 (相当于之前的 overridePendingTransition() 方法设置)
ARouter.getInstance().build(path).withTransition(R.anim_slide_in,R.anim_slide_out);
复制代码
新动画: 使用 withOptionsCompat 方法即可(Android5.0 新出的转场动画)
- ActivityOptionsCompat compat = ActivityOptionsCompat.makeScaleUpAnimation(view, view.getWidth() / 2, view.getHeight() / 2, 0, 0);
- ARouter.getInstance().build("path").withOptionsCompat(compat).navigation();
复制代码
3.4ARouter 处理跳转过程的结果
ARouter 可以让我们处理跳转过程的结果, 什么用呢? 就是你找到目标之后要进行什么操作.
- ARouter.getInstance().build("/module/jumpTestActivity2").navigation(null,new NavigationCallback() {
- @Override
- public void onFound(Postcard postcard) {
- // 找到目标后进行的操作
- }
- @Override
- public void onLost(Postcard postcard) {
- // 找不到目标进行的操作
- }
- });
复制代码
补充说明: 在最新 api 中已经是四个方法了!
- ARouter.getInstance().build("/test/activity").navigation(this, new NavigationCallback() {
- @Override
- public void onFound(Postcard postcard) {
- // 找到队应的内容的时候
- Log.e("done", "onFound:");
- }
- @Override
- public void onLost(Postcard postcard) {
- // 没有找到对应的内容的时候
- Log.e("done", "onLost:");
- }
- @Override
- public void onArrival(Postcard postcard) {
- // 跳转成功
- Log.e("done", "onArrival:");
- }
- @Override
- public void onInterrupt(Postcard postcard) {
- // 拦截操作
- Log.e("done", "onInterrupt:");
- }
- });
复制代码
这里可以在 onLost 中去处理 "位置页面" 的跳转结果, 比如升级 APP 之类的话术.
3.5 携带结果的 Activity
ARouter.getInstance().build("/test/activity").navigation(this,10);
复制代码
后面那个参数就是请求码, 别的和之前的都一样.
3.6 组的概念
在 ARouter 中有个组的概念, 什么意思呢? 就是在构建路由请求的时候, 可以指定分组. 其实这个分组本来就是有个你像 path=/test/activity test 就相当是分组, 但是也可以使用 group 进行分组, 像下面这段代码:
@Route(path = "/test/activity", group = "app")
复制代码
这里需要强调一下, 如果你设置了相应的分组, 那么在进行跳转的时候, 一定要使用 ARouter.getInstance().build(path, group)进行跳转, 否则无法找到相应的跳转
3.7 重写跳转 URL 实现重定向
可以重新定向你的 URL 地址
- @Route(path = "/test/activity2")
- public class PathReplaceServerImp implements PathReplaceService {
- @Override
- public String forString(String path) {
- path = "/test/activity2";
- return path;
- }
- @Override
- public Uri forUri(Uri uri) {
- return null;
- }
- @Override
- public void init(Context context) {
- Log.e("done", "init: 这里是初始化的时候执行的方法");
- }
- }
复制代码
这里说明一下: 上面得 path 一定要加上一个任意项目中出现得注解即可, 如果项目中没有出现得话会报空指针异常的. 通过上面的代码, 就可以更改项目中跳转时候的 path 和 URL 地址了.
3.8ARouter 拦截器
ARouter 的拦截器可以在 navigation 的过程中拦截请求, 并进行一系列的处理 , 是一种 AOP 的编程模式 (应用场景为检查登陆状态等) 要实现拦截器, 首先我们需要实现 IInterceptor 接口, 并使用 Interceptor 注解标记我们的拦截器, 并传入 priority 优先级参数(数字越小, 优先级越高), 其实拦截器就是实现了一个接口去进行回调的!
- public class TestInterceotor implements IInterceptor {
- @Override
- public void process(Postcard postcard, final InterceptorCallback callback) {
- if (postcard.getPath().equals("/test/activity")) {
- callback.onContinue(postcard);
- } else {
- callback.onContinue(postcard);
- }
- }
- @Override
- public void init(Context context) {
- Log.e("done", "init: 初始化调用");
- }
- }
复制代码
这里说明几点内容:
首先 process 这个方法是处理拦截内容的, 这里我判断了一个相应的注解路由, 如果跳转的是相应的路径, 那么进行拦截.
其次 callback.onContinue(postcard)这个要注意, 这句话的含义就是交由路由去处理, 如果这里不写这句话的话, 路由就终止了.
init 方法是全局只执行一次, 这里为什么这么设计我也不知道, 应该是用到相应的内容了吧! 原谅我是一个菜鸟
如果你想加入相应的等级的话在类的上面加入如下注解 **@Interceptor(priority = 7)** 其实就是设置拦截器等级的, 这里为什么又拦截器的等级呢? 主要是为了让拦截器一级一级的向下传递. 这样就有了多级的拦截器.
上面的内容只是简单的用到了拦截器, 但是理解起来毕竟又一些晦涩, 当直接说让你实现登陆的拦截, 你怎么实现, 开始的时候我也觉得简单, 但是当自己写的时候, 我发现这个问题真不是看上去那么简单. 这里我先把内容拦截器的代码都放上, 然后我在讲解!
首次跳转的逻辑
- ARouter.getInstance().build("/test/activity").navigation(this, new NavCallback() {
- @Override
- public void onArrival(Postcard postcard) {
- }
- @Override
- public void onInterrupt(Postcard postcard) {
- Log.e(TAG, "onInterrupt: 这个方法是拦截器执行之后才执行的");
- }
- });
复制代码
拦截器的代码:
- @Interceptor(priority = 7)
- public class TestInterceotor implements IInterceptor {
- @Override
- public void process(Postcard postcard, final InterceptorCallback callback) {
- if (postcard.getPath().equals("/test/activity")) {
- Log.e("done", "process: main2Activity");
- if (APP.isLogin) {/* 已经登陆 */
- callback.onContinue(postcard);
- } else {/* 没有登陆 */
- ARouter.getInstance().build("/test/activity2")
- .withString("name", postcard.getPath()).navigation();
- }
- Log.e("done", "process: 执行完了");
- } else {
- Log.e("done", "process: 这个方法什么时候执行");
- callback.onContinue(postcard);
- }
- }
- @Override
- public void init(Context context) {
- Log.e("done", "init: 初始化调用");
- }
- }
复制代码
模拟登陆的 Activity
- @Route(path = "/test/activity2")
- public class Main3Activity extends AppCompatActivity {
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main3);
- ARouter.getInstance().inject(this);
- }
- public void click(View view) {
- APP.isLogin = true;
- ARouter.getInstance().build("/test/activity").navigation();
- finish();
- }
- }
复制代码
这里第一次跳转的时候, 由于拦截器使得没有登陆的逻辑就跳转到了登陆页面, 之后我在登陆页面模拟了一次登陆的操作, 然后关闭这个页面之前, 我又重新跳转了目标页面, 这次由于已经登陆了, 所以会直接继续执行跳转了目标页面. 这里说的挺简单的, 有一个回调我还没有搞清楚, onInterrupt 这个回调之后有什么用, 其实这里也可以传入一个字段, 然后跳转的时候直接传入这个字段, 这个字段主要是保存要跳转的页面的数据, 之后就能直接跳转了. 这样就解决了耦合的问题.
3.9 在拦截器中添加额外的参数
@Route(path = "/test/activity", extras = 0;/* 注意这里是 int 类型的参数 */)
复制代码
说明一下: 这个是在目标的 Activity 页面添加的额外参数, 之后会在拦截器内生效.
总结
其实关于这个框架还有很多问题我没有理解, 但是基本的一些内容都已经讲解了, 其实接触这个框架主要是当初看见组件化开发的时候, 看到了这个框架, 其实在项目中使用也可以, 整体管理了跳转. 写的挺乱的, 感谢大家抽出宝贵时间来阅读, 有什么不对的地方希望指正.
来源: https://juejin.im/post/5b67bacaf265da0f54054944