本文主要介绍 Android 轻量级路由方案 的实现过程;
什么是路由协议?路由协议就是约定一套路径解析的规则,然后大家都遵循这个规则来进行页面跳转,从而达到动态和解耦的目的。
路由的存在有什么意义?
多模块,组件化,插件化开发时,使用路由进行解耦,组件之间遵循约定好的路由协议进行跳转,不再需要互相依赖。
混合开发时,
Web
端使用约定好的路由路径,可以方便跳转app
内各个页面并进行参数传递。
在 GitHub
上已经有很多相当成熟的路由框架,他们支持编译时注解路径,支持隐式跳转,支持跳转到 Fragment
,支持自定义解析等等… 可以说非常强大了。。
那我为啥还要自己写?主要还是因为,我们要知其然(知道轮子怎么用),知其所以然(知道轮子怎么造)。另外虽然我写的功能不如那些框架强大,但是也更轻量,完成路由的生成、解析和跳转,大约只有 300 行代码,用来完成简单的路由需求也是不错的选择。
我并没有给这个功能单独创建一个工程,因为他太轻量了,我把他集成在了我常用开发库中,本文相关的源代码可以在 GitHub-DevKitSample 中查看。
总的来说这个路由方案的核心的原理就是对路径进行解析,然后生成 intent
,设置参数,进行页面跳转,同时又要支持使用参数,配置生成跳转的路由路径,感谢强大的 Uri
,简化了我很多解析的过程。
路由协议
一个路由路径应该有 Scheme
、Authority
、Path
、QueryParam
几部分组成,他们以下面的形式组装。
1 | Scheme://Authority/Path?QueryParam |
比如下面的 https
协议的路径,Scheme
就是 https
,Authority
就是 www.baidu.com
,Path
就是 test/list
,QueryParam
以 key=value
的形式表现,如 id=100
。
1 | https://www.baidu.com/test/list?id=100&key=value |
因此我们可以定制自己的协议,作为应用内跳转的解析方式,比如定义下面的协议:
1 | chendong://test.march.com/page/1?id=100 |
定制协议
我们在 Android
中进行数据传递时需要知道参数的类型,而这些仅仅靠字符串的路径是无法表达的,因此我们需要对 QueryParam
的声明形式进行如下约定,在 QueryParam
的 key
中需要表达数据的类型。
int | long | boolean | float | double | String | Object |
---|---|---|---|---|---|---|
i-key | l-key | b-key | f-key | d-key | s-key | o-key |
那么我们就会有如下的一个路径,参数仍然是 key-value
的形式,只不过 key
的写法我们是有约定要求的。
1 | chendong://testJs.march.com/page/1?i-iKey=10&f-fKey=1.25&l-lKey=10000000000&d-dKey=1.23456789&b-bKey=true&s-sKey=test |
当路径为 /page/pageId
这种路径时表示是一个页面跳转,其中 pageId
为页面的唯一标示,至于 pageId
和页面的唯一映射,需要提前配置起来,我们会存储以下两个映射 map
。
1 | // 存储 pageId - Activity.class 的映射 |
解析 pageId
首先将路径转换为 Uri
1 | Uri uri = Uri.parse(url); |
接下来我们需要进行 pageId
的解析,我们只有获取到 pageId
才能确认跳转的是哪个页面,使用正则来进行解析。
1 | // 解析 pageId |
解析传递的参数
声明以下几种数据类型的标示
1 | private static final String TYPE_I = "i"; |
定义一个数据类型,除了存储 key-value
,我们还需要将数据的类型分离出来存储
1 | private static class Param { |
解析参数,使用 Uri
的几个 api
和简单的正则,将 type
,key
,value
三部分分离出来存储起来,so easy ~
1 | // 解析参数 |
构建跳转的 intent
我们已经拿到了想要跳转的界面,直接创建跳转的 intent
1 | // find class |
向 intent
中添加传递的参数
1 | // parse params |
进行页面跳转,兼容了一下 startActivityForResult()
的情况。
1 | // 启动 activity |
展示一下完整的流程
1 | public static boolean goFrom(Context context, String url, int reqCode) { |
生成跳转的路由路径
我们支持使用路由路径跳转的同时,也要支持配置参数生成跳转的路由路径。同样借助 Uri
的相关 api
,这个操作并不困难。
1 | // url 构建器 |
我们需要使用 Router
中配置的 Scheme
、Authority
和页面映射。
1 | public static RouterUrlBuilder newRouterUrlBuilder(Class targetActivity) { |
然后我们可以这样配置传递的参数
1 | String url = Router.newRouterUrlBuilder(HomeActivity.class) |
Usage
配置 Scheme
、Authority
和页面映射
1 | new Router.RouterConfig("chendong", "testJs.march.com") |
根据路径跳转
1 | String url = "chendong://testJs.march.com/page/1?i-iKey=10&f-fKey=1.25&l-lKey=10000000000&d-dKey=1.23456789&b-bKey=true&s-sKey=test"; |
生成路由路径
1 | String jumpUrl = Router.newRouterUrlBuilder(HomeActivity.class)s |
我们可以在 html
页面中使用路由路径进行 app
内页面跳转
1 | <a href="chendong://testJs.march.com/page/2?i-id=10&s-name"> 打开首页 </a> |
截断路径进行跳转
1 | mWebView.setWebViewClient(new WebViewClient() { |
todo
现在只是简化的版本,支持基本的功能,需要完善和验证的地方还有很多。
我把他集成在了我常用开发库中,本文相关的源代码可以在 GitHub-DevKitSample 中查看。