探索Android路由框架-ARouter之基本使用(一)

   本文已独家授权 郭霖 ( guolin_blog ) 公众号发布!

    本文意在快速集成并掌握阿里Android技术团队开源的一款路由框架。这款路由框架可以为我们的应用开发提供更好更丰富的跳转方案。比如支持解析标准URL进行跳转,并自动注入参数到目标页面中;支持添加多个拦截器,自定义拦截顺序(满足拦截器设置的条件才允许跳转,所以这一特性对于某些问题又提供了新的解决思路)。

    本文示例代码基于ARouter框架最新1.3版本进行编写。介于篇幅的原因将其分成两篇,第一篇主要介绍该框架的配置以及基本使用;第二篇主要的内容是通过现象去研究路由框架的源码。

    如果对ARouter的使用已经烂熟于心,那么可以直接进入第二篇 ARouter源码分析 

前言:

    首先借用阿里云栖社区的一段话:我们所使用的原生路由方案一般是通过显式intent和隐式intent两种方式实现的(这里主要是指跳转Activity or Fragment)。在显式intent的情况下,因为会存在直接的类依赖的问题,导致耦合非常严重;而在隐式intent情况下,则会出现规则集中式管理,导致协作变得非常困难。一般而言配置规则都是在Manifest中的,这就导致了扩展性较差。除此之外,使用原生的路由方案会出现跳转过程无法控制的问题,因为一旦使用了StartActivity()就无法插手其中任何环节了,只能交给系统管理,这就导致了在跳转失败的情况下无法降级,而是会直接抛出运营级的异常。这时候如果考虑使用自定义的路由组件就可以解决以上问题,比如通过URL索引就可以解决类依赖的问题;通过分布式管理页面配置可以解决隐式intent中集中式管理Path的问题;自己实现整个路由过程也可以拥有良好的扩展性,还可以通过AOP的方式解决跳转过程无法控制的问题,与此同时也能够提供非常灵活的降级方式。

ARouter官方项目地址

添加依赖

添加依赖

javaCompileOptions {

annotationProcessorOptions {

arguments = [moduleName :project.getName() ]

} }

compile'com.alibaba:arouter-api:1.3.1'

annotationProcessor'com.alibaba:arouter-compiler:1.1.4'

初始化

官方建议我们在Application里面进行ARouter初始化,于是乎就有了以下代码:


初始化

然后别忘记了在清单文件里面配置自定义的Application和我们的Activity。

项目依赖导入和初始化就已经完成了,下面就开始正式的功能使用以及简单的封装。

开始使用:

1)首先:在Activity/Fragment类上面写上 Route path 注解。

      注意:这里的路径需要注意的是至少需要有两级,/xx/xx

2)然后:在Activity/Fragment类里面进入Arouter 注入,也就是:ARouter.getInstance().inject(this);

3)接着:目标的Activity类上面需要声明Route path 注解,以此对应(跳转如果不对应路径,框架会Toast说路径不匹配)

上述说明的简单使用如下图:

简单使用

理论上来说,如果只是进行简单的跳转页面,

ARouter.getInstance().build(“目标界面对应的路径”).navigation(); 就这样一行代码即可完成跳转界面。

好了,看到这里我们就会发现,路径的标签如果多了就不是很好管理,(所以更好的选择是写一个类,在这个类里面统一管理和维护路径标签,不仅利于维护也方便后期拓展,看到路径就一目了然,哇~这个路径对应的是登录界面,这个路径对应的是详情界面);其次,每个页面的注入,也就是ARouter.getInstance().inject(this);这句代码出现的几率会写的很多,(而且一般的常规逻辑是有注入就有解绑或者释放资源)所以我们应该简单封装起来提高效率

简单封装

首先是路径管理:

路径统一管理

然后是注入封装:

这里多提一嘴,优秀的第三方框架如果一般有注入或者绑定的API,那与之对应的一般就会有释放或者解绑资源的API。(这样做的本质是优化内存)其中, ARouter.getInstance().destroy( ) ; 这个API一目了然,就是释放资源的API。下面就是开始注入和释放资源的封装:

注入封装

笔者在Activity的基类里面通过生命周期进行了注入和解绑,但是项目运行后发现了一个问题,就是如果在onDestroy()里面调用了 ARouter.getInstance().destroy( ) ; 在进入目标Activity之后,然后按back键返回原界面的时候,APP会报错崩溃,下面是崩溃日志:

    仔细一看,初始化有问题?在前面我们说到在自定义Application里面已经初始化了ARouter,且在清单文件里面配置了自定义的Application,但是依旧提示没有初始化,这就纳了个闷?然后想了想,可能是 ARouter.getInstance().destroy( );这行代码的使用位置可能用错了。然后既然是在Application里面进行的初始化,那么就可以将这行释放资源的代码,写在Application生命周期的onTerminate( )里面,果不其然,项目运行后就没什么问题了。当然,这是我自己的思路,有更好的意见和想法请在评论区指出,谢谢。

初始化

封装完毕了路径标识以及注入释放等基本功能,我们回到ARouter的基本使用:

简单页面跳转

如果只是简单的页面跳转,一行代码即可完成,如下图

简单跳转 - 1

其中,build里面是页面的标签路径,对应的就是目标Activity的这里,也就是类注释标签路径要一致:

Ps:不要忘了在清单文件里面配置Activity。

带参数的界面跳转

    带参数的跳转是很常见的功能,Android可以通过Bundle去传递参数,如果使用ARouter框架,它传递参数通过以下去操作:

    ARouter传递对象的时候,首先该对象需要Parcelable或者Serializable序列化,可能Parcelable这个序列化大家觉得手写起来比较麻烦,但是Android Studio已经有一些插件帮我们自动生成Parcelable序列化了(因为Android用Parcelable序列化优势会更加明显一些)

    字符串、char、int等基本数据类型当然都是可以传递的

    当然,它也可以直接传Bundle、数组、列表等很多对象,传递类型如下图

传递类型

携带参数的界面跳转,简单使用如下图

跳转传递参数

其中,第一个参数代表的是参数的key,第二个参数对应的是我们要传递的属性值,也就是value

那么目标界面如何获取传递过来的值?

这个时候,我们需要在目标界面,使用Autowired注解,

Autowired 注解

这样就可以获取到传递过来的值了

获取属性值

值得注意的是,只有当 @Autowired(name = "test"),也就是key标签一致的情况下,才可以获取到对象的值,如果不写标签名,结果会为null,

Autowired 注解

所以为了规避每一个可能会遇到的风险,建议在@Autowired里面 都写上与之对应具体的key名。

界面跳转动画

直接调用withTransition,里面传入两个动画即可(R.anim.xxx)

跳转动画

使用URI进行跳转

ARouter框架也可以使用URI进行匹配跳转,代码也很少,只需匹配路径一致即可完成跳转:

URI - 匹配跳转

Fragment跳转

Fragment的跳转也可以参照Activity跳转,第一步依旧是先写上类注释,然后是强转,代码如下

Fragment跳转

进阶用法之拦截器:

    拦截器是ARouter这一款框架的亮点。说起拦截器这个概念,可能印象更加深刻的是OkHttp的拦截器,OkHttp的拦截器主要是用来拦截请求体(比如添加请求Cookie)和拦截响应体(判断Token是否过期),在真正的请求和响应前做一些判断和修改然后在去进行操作,大抵这就是拦截器的简单概念。那么,ARouter框架的拦截器是怎么实现的?

    ARouter的拦截器,是通过实现 IInterceptor接口,重写init()和process()方法去完成拦截器内部操作的。

    首先我们定义两个拦截器:

拦截器 - 1
拦截器 - 2

    首先,定义ARouter拦截器必须要使用Interceptor类注解。注解里面的 priority(也就是红色框) 这个是声明拦截器的优先级、里面的属性值是int类型。既然是定义优先级,我们这里定义2个拦截器来测试看看优先级是如何区分谁先谁后的?两个拦截器写完之后,运行下项目看下效果:

拦截器初始化先后顺序

    结论 1:根据实验得知,使用Interceptor类注解的priority数值越小,越先执行,优先级越高。(四大组件中的广播,优先级的取值是 -1000到1000,数值越大优先级越高)

    那么,还有一种情况,如果两个拦截器定义的优先级都是一样的,那么谁的优先级会高?是根据类的字符串长度来判断嘛还是别的条件来判断的??

    首先,将上面的拦截器的优先级改成一样(都改成1),项目编译试试,结果发现项目就会直接报错!

同优先级问题

    看下具体的错误原因:

相同优先级错误原因

    翻译过来就是他们使用了相同的优先级,所以:

    结论 2:如果两个拦截器的优先级一样,项目编译就会报错。所以,不同拦截器定义的优先级属性值不能相同

    我们到这两个拦截器里面加一点筛选条件的代码:

拦截器 - 3

    将这段代码加进去之后,重新运行App,打印日志结果如下:

拦截器 - 执行流程

    为了方便看清运行的日志,我用三种颜色的箭头去对应。首先是两个拦截器的初始化,然后,调用了NavigationCallback这个回调函数里面的onFound(),然后执行了拦截器里面的process()方法;当拦截器的process()方法执行完毕以后,最终回调了NavigationCallback里面的onArrival()方法。拦截器的工作流程大抵就是这样。那么,NavigationCallback这个又是什么?实际上,NavigationCallback这个简单理解就是ARouter在路由跳转的过程中,我们可以监听路由的一个具体过程。它一共有四个方法:

NavigationCallback

那么,这个回调里面的 Postcard 又是什么意思?点进去源码看看,类注释写的一目了然:

Postcard类注释

红色框翻译过来的类注释就是:一个包含路线图的容器。

既然是路线图的容器,那肯定有些API会获取到相应的信息,

Group简单使用

    通过Postcard可以获取到路径的组以及全路径,那么,路径的组(Group)又是什么?是这样,一般来说,ARouter在编译期框架扫描了所有的注册页面/字段/拦截器等,那么很明显运行期不可能一股脑全部加载进来,这样就太不和谐了。所以就使用分组来管理,我们的类标签里面的注释,对于group默认是 “ ”(空字符串)如下图:

    在 Group简单使用 这张图上面,根据日志,打印了分组的信息,可以发现Group的值默认就是第一个 /  /(两个分隔符) 之间的内容。

    那么,我们也可以自定义分组,来进行界面跳转,所以ARouter又提供了一种解决方案:

自定义分组 实现跳转界面

如果使用自定义分组来跳转界面,只需要在源代码改动以下三个位置:

1:类注解新增 group,赋值我们自定义的组名,(依旧统一写在一个类里面这样便于管理)

自定义分组跳转界面 - 1

2:在build方法里面(这是一个方法重载),添加我们的与之对应的组名

自定义分组跳转 - 2

3:在被跳转的Activity里面的类注释,加上同样的组名

自定义分组跳转 - 3

通过上面三个步骤即可完成 自定义分组 来完成界面跳转

自定义分组显示结果

通过日志显示,这里的组名已经被我们更改成自定义分组且成功完成了跳转。

ARouter如何实现类似startActivityForResult()?

这种应用场景也是很常见的,那ARouter该如何实现?

第一步:为了方便看效果,我们在第一个Activity设置requestCode 为123,

onActivityResult

第二步:需要在跳转的navigation方法(这是一个方法重载)里面的第二个参数,设置我们定义的requestCode,(通过匹配requestCode 来实现该功能)

第三步:在第二个界面的setResult方法里面,写上对应的resultCode,这里就不展示Intent数据了

综合上面三个步骤,项目编译运行,跳转到第二个界面然后返回上一个界面,日志成功打印:

ARouter路由框架的基本使用就介绍到这里,源码分析请看第二篇。

探索Android路由框架-ARouter之深挖源码

如果这篇文章对您有开发or学习上的些许帮助,希望各位看官留下宝贵的star,谢谢。

Ps:著作权归作者所有,转载请注明作者, 商业转载请联系作者获得授权,非商业转载请注明出处(开头或结尾请添加转载出处,添加原文url地址),文章请勿滥用、开源项目仅供学习交流、也希望大家尊重笔者的劳动成果,谢谢。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,425评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,058评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,186评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,848评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,249评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,554评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,830评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,536评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,239评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,505评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,004评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,346评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,999评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,060评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,821评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,574评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,480评论 2 267

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,565评论 25 707
  • 开发一款App,总会遇到各种各样的需求和业务,这时候选择一个简单好用的轮子,就可以事半功倍 前言 上面一段代码,在...
    WangDeFa阅读 65,459评论 44 199
  • 今天去南站把去拉萨的车票退了,好在最后一天带着身份证,没有额外费用产生。 随后去了国际妇幼保健院,还是很感恩在收费...
    爱思塔阅读 194评论 1 0