【转载】ARouter-万能路由协议
Github源码地址:https://github.com/alibaba/ARouter
一、功能介绍
- 支持直接解析标准URL进行跳转,并自动解析参数注入
- 支持多模块工程使用
- 支持添加多个拦截器,自定义拦截顺序
- 支持依赖注入,可单独作为依赖注入框架使用
- 支持InstantRun
- 支持MultiDex(Google方案)
- 映射关系按组分类、多级管理,按需初始化
- 支持用户指定全局降级与局部降级策略
- 页面、拦截器、服务等组件均自动注册到框架
二、典型应用
- 从外部URL映射到内部页面,以及参数传递与解析
- 跨模块页面跳转,模块间解耦
- 拦截跳转过程,处理登陆、埋点等逻辑
- 跨模块API调用,通过控制反转来做组件解耦
三、基础功能
添加依赖和配置
android {
defaultConfig {
...
javaCompileOptions {
annotationProcessorOptions {
arguments = [ moduleName : project.getName() ]
}
}
}
} dependencies {
compile 'com.alibaba:arouter-api:x.x.x'
annotationProcessor 'com.alibaba:arouter-compiler:x.x.x'
...
}
// 旧版本gradle插件(< 2.2),可以使用apt插件,配置方法见文末'其他#4'添加注解
// 在支持路由的页面上添加注解(必选)
// 这里的路径需要注意的是至少需要有两级,/xx/xx
@Route(path = "/test/activity")
public class YourActivity extend Activity {
...
}初始化SDK
if (isDebug()) {
ARouter.openLog(); // 打印日志
ARouter.openDebug(); // 开启调试模式(如果在InstantRun模式下运行,必须开启调试模式!线上版本需要关闭,否则有安全风险)
}
ARouter.init(mApplication); // 尽可能早,推荐在Application中初始化发起路由操作
// 1. 应用内简单的跳转(通过URL跳转在'进阶用法'中)
ARouter.getInstance().build("/test/activity").navigation(); // 2. 跳转并携带参数
ARouter.getInstance().build("/test/1")
.withLong("key1", 666L)
.withString("key3", "888")
.navigation();添加混淆规则(如果使用了Proguard)
-keep public class com.alibaba.android.arouter.routes.**{*;}
-keep class * implements com.alibaba.android.arouter.facade.template.ISyringe{*;}
四、进阶用法
通过URL跳转
// 新建一个Activity用于监听Schame事件,之后直接把url传递给ARouter即可
public class SchameFilterActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); Uri uri = getIntent().getData();
ARouter.getInstance().build(uri).navigation();
finish();
}
} // AndroidManifest.xml
<activity android:name=".activity.SchameFilterActivity">
<!-- Schame -->
<intent-filter>
<data
android:host="m.aliyun.com"
android:scheme="arouter"/> <action android:name="android.intent.action.VIEW"/> <category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
</intent-filter>
</activity>解析URL中的参数
// 为每一个参数声明一个字段,并使用 @Autowired 标注
@Route(path = "/test/activity")
public class Test1Activity extends Activity {
@Autowired
public String name;
@Autowired
private int age;
@Autowired(name = "girl") // 通过name来映射URL中的不同参数
private boolean boy; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ARouter.getInstance().inject(this); // ARouter会自动对字段进行赋值,无需主动获取
Log.d("param", name + age + boy);
}
}声明拦截器(拦截跳转过程,面向切面编程)
// 比较经典的应用就是在跳转过程中处理登陆事件,这样就不需要在目标页重复做登陆检查
// 拦截器会在跳转之间执行,多个拦截器会按优先级顺序依次执行
@Interceptor(priority = 8, name = "测试用拦截器")
public class TestInterceptor implements IInterceptor {
@Override
public void process(Postcard postcard, InterceptorCallback callback) {
...
callback.onContinue(postcard); // 处理完成,交还控制权
// callback.onInterrupt(new RuntimeException("我觉得有点异常")); // 觉得有问题,中断路由流程 // 以上两种至少需要调用其中一种,否则不会继续路由
} @Override
public void init(Context context) {
// 拦截器的初始化,会在sdk初始化的时候调用该方法,仅会调用一次
}
}处理跳转结果
// 使用两个参数的navigation方法,可以获取单次跳转的结果
ARouter.getInstance().build("/test/1").navigation(this, new NavigationCallback() {
@Override
public void onFound(Postcard postcard) {
...
} @Override
public void onLost(Postcard postcard) {
...
}
});自定义全局降级策略
// 实现DegradeService接口,并加上一个Path内容任意的注解即可
@Route(path = "/xxx/xxx")
public class DegradeServiceImpl implements DegradeService {
@Override
public void onLost(Context context, Postcard postcard) {
// do something.
} @Override
public void init(Context context) { }
}为目标页面声明更多信息
// 我们经常需要在目标页面中配置一些属性,比方说"是否需要登陆"之类的
// 可以通过 Route 注解中的 extras 属性进行扩展,这个属性是一个 int值,换句话说,单个int有4字节,也就是32位,可以配置32个开关
// 剩下的可以自行发挥,通过字节操作可以标识32个开关,通过开关标记目标页面的一些属性,在拦截器中可以拿到这个标记进行业务逻辑判断
@Route(path = "/test/activity", extras = Consts.XXXX)通过依赖注入解耦:服务管理(一) 暴露服务
// 声明接口,其他组件通过接口来调用服务
public interface HelloService extends IProvider {
String sayHello(String name);
} // 实现接口
@Route(path = "/service/hello", name = "测试服务")
public class HelloServiceImpl implements HelloService { @Override
public String sayHello(String name) {
return "hello, " + name;
} @Override
public void init(Context context) { }
}通过依赖注入解耦:服务管理(二) 发现服务
public class Test {
@Autowired
HelloService helloService; @Autowired(name = "/service/hello")
HelloService helloService2; HelloService helloService3; HelloService helloService4; public Test() {
ARouter.getInstance().inject(this);
} public void testService() {
// 1. (推荐)使用依赖注入的方式发现服务,通过注解标注字段,即可使用,无需主动获取
// Autowired注解中标注name之后,将会使用byName的方式注入对应的字段,不设置name属性,会默认使用byType的方式发现服务(当同一接口有多个实现的时候,必须使用byName的方式发现服务)
helloService.sayHello("Vergil");
helloService2.sayHello("Vergil"); // 2. 使用依赖查找的方式发现服务,主动去发现服务并使用,下面两种方式分别是byName和byType
helloService3 = ARouter.getInstance().navigation(HelloService.class);
helloService4 = (HelloService) ARouter.getInstance().build("/service/hello").navigation();
helloService3.sayHello("Vergil");
helloService4.sayHello("Vergil");
}
}
五、更多功能
初始化中的其他设置
ARouter.openLog(); // 开启日志
ARouter.openDebug(); // 使用InstantRun的时候,需要打开该开关,上线之后关闭,否则有安全风险
ARouter.printStackTrace(); // 打印日志的时候打印线程堆栈详细的API说明
// 构建标准的路由请求
ARouter.getInstance().build("/home/main").navigation(); // 构建标准的路由请求,并指定分组
ARouter.getInstance().build("/home/main", "ap").navigation(); // 构建标准的路由请求,通过Uri直接解析
Uri uri;
ARouter.getInstance().build(uri).navigation(); // 构建标准的路由请求,startActivityForResult
// navigation的第一个参数必须是Activity,第二个参数则是RequestCode
ARouter.getInstance().build("/home/main", "ap").navigation(this, 5); // 直接传递Bundle
Bundle params = new Bundle();
ARouter.getInstance()
.build("/home/main")
.with(params)
.navigation(); // 指定Flag
ARouter.getInstance()
.build("/home/main")
.withFlags();
.navigation(); // 觉得接口不够多,可以直接拿出Bundle赋值
ARouter.getInstance()
.build("/home/main")
.getExtra(); // 使用绿色通道(跳过所有的拦截器)
ARouter.getInstance().build("/home/main").greenChannal().navigation(); // 使用自己的日志工具打印日志
ARouter.setLogger();获取原始的URI
String uriStr = getIntent().getStringExtra(ARouter.RAW_URI);
重写跳转URL
// 实现PathReplaceService接口,并加上一个Path内容任意的注解即可
@Route(path = "/xxx/xxx") // 必须标明注解
public class PathReplaceServiceImpl implements DegradeService {
/**
* For normal path.
*
* @param path raw path
*/
String forString(String path) {
return path; // 按照一定的规则处理之后返回处理后的结果
} /**
* For uri type.
*
* @param uri raw uri
*/
Uri forUri(Uri uri) {
return url; // 按照一定的规则处理之后返回处理后的结果
}
}
六、其他
路由中的分组概念
- SDK中针对所有的路径(/test/1 /test/2)进行分组,分组只有在分组中的某一个路径第一次被访问的时候,该分组才会被初始化
- 可以通过 @Route 注解主动指定分组,否则使用路径中第一段字符串(/*/)作为分组
注意:一旦主动指定分组之后,应用内路由需要使用 ARouter.getInstance().build(path, group) 进行跳转,手动指定分组,否则无法找到
@Route(path = "/test/1", group = "app")
拦截器和服务的异同
- 拦截器和服务所需要实现的接口不同,但是结构类似,都存在 init(Context context) 方法,但是两者的调用时机不同
- 拦截器因为其特殊性,会被任何一次路由所触发,拦截器会在ARouter初始化的时候异步初始化,如果第一次路由的时候拦截器还没有初始化结束,路由会等待,直到初始化完成。
- 服务没有该限制,某一服务可能在App整个生命周期中都不会用到,所以服务只有被调用的时候才会触发初始化操作
Jack 编译链的支持
因为不想让用户主动设置一堆乱七八糟的参数,在获取模块名的时候使用javac的api,使用了Jack之后没有了javac,只能让用户稍稍动动手了- 现在任何情况下都需要在build.gradle中配置moduleName了。。。。
旧版本gradle插件的配置方式
apply plugin: 'com.neenbedankt.android-apt' buildscript {
repositories {
jcenter()
} dependencies {
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.4'
}
} apt {
arguments {
moduleName project.getName();
}
} dependencies {
compile 'com.alibaba:arouter-api:x.x.x'
apt 'com.alibaba:arouter-compiler:x.x.x'
...
}注意:应用宝使用乐固加固后,ARouter的启动器会失效,所以启动器需要改成:
public static void start(Context context, int communityId, String communityName) {
Intent starter = new Intent(context, CommunityApplyListActivity.class);
starter.putExtra("communityId", communityId);
starter.putExtra("communityName", communityName);
if (!(context instanceof Activity)) {
starter.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
context.startActivity(starter);
}
【转载】ARouter-万能路由协议的更多相关文章
- 【转载】万能adapter
adapter总是自己写,其实使用现成的框架会节省不少代码 原文地址:https://github.com/hongyangAndroid/baseAdapter base-adapter Andro ...
- 草根程序员如何进入BAT
首页 最新文章 IT 职场 前端 后端 移动端 数据库 运维 其他技术 - 导航条 - 首页 最新文章 IT 职场 前端 - JavaScript - HTML5 - CSS 后端 - Pyt ...
- [转载]Ubuntu 安装 万能五笔 输入法
原文地址:Ubuntu 安装 万能五笔 输入法作者:庖丁解牛 paul@paul-desktop:~/scripts$ cat ins-ibus-wnwb.sh #!/bin/sh set -e cd ...
- 【转载】可被路由的协议 & 路由协议 & 不可被路由的协议 的区别
原文地址:可被路由的协议 & 路由协议 & 不可被路由的协议 的区别 术语routed protocol(可被路由的协议)和routing protocol(路由协议)经常被混淆.可被 ...
- 转载:对比Angular/jQueryUI/Extjs:没有一个框架是万能的
Angular不能做什么?对比Angular/jQueryUI/Extjs 框架就好比兵器,你得明白你手里拿的是屠龙刀还是倚天剑,刀法主要是砍,剑法主要是刺.对于那些职业喷子和脑残粉,小僧送你们两个字 ...
- 打造android偷懒神器———RecyclerView的万能适配器
转载请注明出处谢谢:http://www.cnblogs.com/liushilin/p/5720926.html 很不好意思让大家久等了,本来昨天就应该写这个的,无奈公司昨天任务比较紧,所以没能按时 ...
- 转载ali面
引言 首先声明,不要再问LZ谁是林萧,林萧就是某著名程序员小说的主角名字. 写这篇文章的目的其实很简单,算是对之前LZ一篇文章的补充和完善. 之前LZ写过一篇<回答阿里社招面试如何准备,顺便谈谈 ...
- 转载:[转]如何学好3D游戏引擎编程
[转]如何学好3D游戏引擎编程 Albert 本帖被 gamengines 从 游戏引擎(Game Engine) 此文为转载,但是值得一看. 此篇文章献给那些为了游戏编程不怕困难的热血青年,它的 ...
- Huge Page 是否是拯救性能的万能良药?
本文将分析是否Huge Page在任何条件下(特别是NUMA架构下)都能带来性能提升. 本博客已经迁移至: http://cenalulu.github.io/ 为了更好的体验,请通过此链接阅读: h ...
随机推荐
- nginx 前后分离,地址重写,url匹配中遇到的问题
我遇到的问题: 前端用vue的路由做页面路由,后台用spring mvc做数据接口,但是遇到路由地址和接口地址无法区分的问题,导致nginx无法正确准发比如: 1)http://127.0.0.1/i ...
- Ubuntu+NDK编译支持HTTPS的libcurl
参考文章:1.NDK环境配置 http://blog.csdn.net/smfwuxiao/article/details/65877092.libcurl的配置修改 http://piggyq.co ...
- libcurl在mingw下编译
通过命令提示符进入 curl-7.27.0 文件夹输入 mingw32-make mingw32 进行生成(这里我只需要普通的功能,于是没有加附加的选项)编译完成后,在 lib 文件夹中会有我们需要的 ...
- OpenCV---像素运算
像素运算 分为算术运算和逻辑运算 算术运算: 加减乘除 调节亮度 调整对比度 逻辑运算: 与或非 遮罩层控制 一:算术运算 import cv2 as cv import numpy as np de ...
- 为VSCODE添加右键菜单
参考:https://blog.csdn.net/GreekMrzzJ/article/details/82194913 1.创建一个名为vscode.reg的空文本文件,填入下列内容 Windows ...
- HDU 3977 斐波那契循环节
这类型的题目其实没什么意思..知道怎么做后,就有固定套路了..而且感觉这东西要出的很难的话,有这种方法解常数会比较大吧..所以一般最多套一些比较简单的直接可以暴力求循环节的题目了.. /** @Dat ...
- ZOJ 3781 Paint the Grid Reloaded 连通块
LINK:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3781 题意:n*m只由OX组成的矩阵,可以选择某一连通块变成另一 ...
- [转]C++中cin、cin.get()、cin.getline()、getline()函数的简单总结
参考原文:http://www.cnblogs.com/flatfoosie/archive/2010/12/22/1914055.html,另外做了一些修改~ 1.cin 2.cin.get() 3 ...
- XML & JSON---iOS-Apple苹果官方文档翻译
技术博客http://www.cnblogs.com/ChenYilong/ 新浪微博http://weibo.com/luohanchenyilong //转载请注明出处--本文永久链接 ...
- C语言易错点
C语言易错点 1.每个C语言程序中main函数是有且只有一个的. 2.算法可以没有输入,但必须要有输出. 3.在函数中不可以再定义函数. 4.break可用于循环结构和switch语句. 5.brea ...