使用
集成ARouter框架
- 添加依赖
- 在项目的根目录下的
build.gradle
文件中,添加ARouter的依赖:
- 在项目的根目录下的
buildscript {
repositories {
google()
mavenCentral()
}
dependencies {
// 其他依赖项...
classpath "com.alibaba:arouter-register:1.5.2"
}
}
allprojects {
repositories {
google()
mavenCentral()
}
}
- 在应用模块的 build.gradle
文件中,添加以下依赖:
dependencies {
// 其他依赖项...
implementation 'com.alibaba:arouter-api:1.5.2'
annotationProcessor 'com.alibaba:arouter-compiler:1.5.2'
}
使用ARouter框架
- 初始化ARouter
- 一般在自定义的
Application
类的onCreate
方法中初始化ARouter,示例代码如下:
- 一般在自定义的
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
if (isDebug()) { // 判断是否是调试模式
ARouter.openLog(); // 开启日志
ARouter.openDebug(); // 开启调试模式
}
ARouter.init(this); // 初始化ARouter
}
private boolean isDebug() {
return BuildConfig.DEBUG;
}
}
- 定义路由路径
- 使用
@Route
注解来定义路由路径,通常在Activity
、Fragment
或其他需要被路由的组件类上添加该注解。例如:
- 使用
@Route(path = "/main/homeActivity")
public class HomeActivity extends AppCompatActivity {
//...
}
- 发起路由跳转
- 在需要进行页面跳转的地方,可以使用
ARouter.getInstance().build()
方法构建一个路由请求,然后调用navigation()
方法进行跳转,示例如下:
- 在需要进行页面跳转的地方,可以使用
ARouter.getInstance().build("/main/homeActivity").navigation();
- 传递参数
- 可以在路由跳转时传递参数。首先在目标
Activity
或Fragment
中定义接收参数的字段,并使用@Autowired
注解标记,然后在发起路由跳转时通过withXXX
方法传递参数,示例如下:
- 可以在路由跳转时传递参数。首先在目标
// 目标Activity
@Route(path = "/main/detailActivity")
public class DetailActivity extends AppCompatActivity {
@Autowired
public String itemId;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_detail);
ARouter.getInstance().inject(this);
// 使用itemId进行相关操作
}
}
// 发起跳转并传递参数
ARouter.getInstance().build("/main/detailActivity")
.withString("itemId", "12345")
.navigation();
- 处理返回结果
- 如果需要在跳转到新页面并返回结果,可以使用
ARouter.getInstance().build()
方法构建路由请求时,调用navigation()
方法的重载版本,传入一个NavigationCallback
回调接口来处理返回结果,示例如下:
- 如果需要在跳转到新页面并返回结果,可以使用
ARouter.getInstance().build("/main/selectActivity")
.navigation(this, new NavigationCallback() {
@Override
public void onFound(Postcard postcard) {
// 找到目标页面
}
@Override
public void onLost(Postcard postcard) {
// 找不到目标页面
}
@Override
public void onArrival(Postcard postcard) {
// 到达目标页面
}
@Override
public void onInterrupt(Postcard postcard) {
// 路由被拦截
}
});
高级功能
- 拦截器****的使用
- 可以定义路由拦截器,用于在路由跳转前进行一些全局的拦截和处理,如权限验证、登录检查等。创建一个类实现
IInterceptor
接口,并使用@Interceptor
注解标记,然后在init
方法中进行拦截逻辑的处理,示例如下:
- 可以定义路由拦截器,用于在路由跳转前进行一些全局的拦截和处理,如权限验证、登录检查等。创建一个类实现
@Interceptor(priority = 7)
public class LoginInterceptor implements IInterceptor {
@Override
public void process(Postcard postcard, InterceptorCallback callback) {
if (isLoggedIn()) {
callback.onContinue(postcard);
} else {
callback.onInterrupt(null);
// 可以跳转到登录页面
ARouter.getInstance().build("/login/loginActivity").navigation();
}
}
@Override
public void init(Context context) {
// 初始化拦截器
}
private boolean isLoggedIn() {
// 判断用户是否登录的逻辑
return false;
}
}
- 动态注册路由
- 除了使用注解定义路由,还可以通过代码动态注册路由,适用于一些需要根据运行时条件动态添加路由的场景。使用
ARouter.getInstance().addRoute()
方法来动态注册路由,示例如下:
- 除了使用注解定义路由,还可以通过代码动态注册路由,适用于一些需要根据运行时条件动态添加路由的场景。使用
ARouter.getInstance().addRoute("/dynamic/activity", DynamicActivity.class);
addRoute("/dynamic/activity", DynamicActivity.class)
:- 这是调用获取到的
ARouter
实例的addRoute
方法,它接受两个参数: - 第一个参数
"/dynamic/activity"
是一个字符串类型的路由路径。这个路径就像是一个地址,当在应用的其他地方发起路由跳转,指定要跳转到这个路径对应的页面或者组件时,ARouter 就会依据这个路径找到对应的目标。路由路径的命名一般按照一定的规范,方便团队成员理解和维护,比如可以按照模块名、页面功能等来定义,例如这里的dynamic
可能表示和动态相关的某个页面,路径名称在整个应用的路由体系里要保证唯一性,避免出现路由冲突的情况。 - 第二个参数
DynamicActivity.class
是一个Class
类型的参数,它指定了路由指向的目标Activity
类(当然也可以是其他组件类,不过常见的是Activity
用于页面跳转场景)。当通过 ARouter 发起的路由请求匹配到"/dynamic/activity"
这个路径时,ARouter 就会实例化这个DynamicActivity.class
对应的Activity
,然后进行页面跳转等相关操作,就如同使用@Route
注解标记DynamicActivity
类并指定相同路径的效果一样。
- 这是调用获取到的
ARouter里Activity之间的跳转
Activity与Activity里的跳转只需调用如下代码,build里的路径,就是我们用标注@Route path标注的路径:
ARouter.getInstance().build("/myapplication/MainActivity").navigation();
从上面代码我们发现。路径"/myapplication/MainActivity",得统一用个常量类管理起来,不然这样找起来,简直费事,如下:
public final class Constance {
public static final String ACTIVITY_PATH_MAIN = "/myapplication/MainActivity";
}
这里除了路径跳转外,从他的参数类型中,还能看到有Uri跳转:
Uri uri = Uri.parse(Constance.ACTIVITY_PATH_MAIN);
ARouter.getInstance().build(uri).navigation();
带参数跳转 & 获取参数
带参数跳转
只需在后面.withString(),即可,里面包含了所有你想传的类型
ARouter.getInstance()
.build("/myapplication/MainActivity")
.withString("name", "lihang")
.withInt("age", 27)
.withSerializable("human", new Person("力哈", "11"))
.navigation();
获取参数
在获取参数页面,注意这里有个大坑:
@Route(path = "/myapplication/SimpleActivity")
public class SimpleActivity extends BaseActivity {
@Autowired()
String name;
@Autowired(name = "age")
int mAge;
// @Autowired(name = "human")这里注意,如果是传Serializable,注解是得不到的。除非是Paceable
Person mPerson;
@Override
public int getContentViewId() {
return R.layout.activity_simple;
}
@Override
public void progressLogic() {
// mPerson = (Person) getIntent().getSerializableExtra("human");
}
}
这里获取参数有3种方式:
- 使用@Autowired标注后,下方的值是之间传值的key。
@Autowired()
String name;
- 使用@Autowired标注后,name = key,name等于之间传值的key,下方参数名随便定
@Autowired(name = "age")
int mAge;
- 带序列化这里有些特殊,如果是Parcelable类型,可以用上方的方法获取。但是如果是Serializable类型,却会发现,没办法获取到。但是这里用我们传统的getIntent也能获取到
我们发现Serializable序列化的对象为null,我们查看withSerializable方法发现其被装进了Bundle
public Postcard withSerializable(@Nullable String key, @Nullable Serializable value) {
mBundle.putSerializable(key, value);
return this;
}
因此换一种方法来取值,发现打印成功
mPerson = (Person) getIntent().getSerializableExtra("human");
携带无序列化对象的界面跳转
没有进行过序列化的对象也可以通过withObject对象进行传递,接收方式相同
NormalTest normalTest = new NormalTest();
normalTest.setName("normal");
ARouter.getInstance()
.build("/app/login")
.withObject("normalTest", normalTest)
.navigation();
但是我们直接使用该方法运行会报错,分析源码发现该方法中用到了SerializationService
public Postcard withObject(@Nullable String key, @Nullable Object value) {
serializationService = ARouter.getInstance().navigation(SerializationService.class);
mBundle.putString(key, serializationService.object2Json(value));
return this;
}
因此我们需要实现该服务
@Route(path = "/service/json")
public class JsonServiceImpl implements SerializationService {
private Gson gson;
@Override
public <T> T json2Object(String input, Class<T> clazz) {
return gson.fromJson(input, clazz);
}
@Override
public String object2Json(Object instance) {
return gson.toJson(instance);
}
@Override
public <T> T parseObject(String input, Type clazz) {
return gson.fromJson(input, clazz);
}
@Override
public void init(Context context) {
gson = new Gson();
}
}
我们可以在里面定义所需的json解析器,再次运行成功打印该对象。那序列化的对象可以使用该方法传递吗?
TestParcelableBean objParcelableBean = new TestParcelableBean();
objParcelableBean.setName("objParcelable");
TestSerializableBean objSerializableBean = new TestSerializableBean();
objSerializableBean.setName("objSerializable");
NormalTest normalTest = new NormalTest();
normalTest.setName("normal");
ARouter.getInstance().build("/app/login")
.withObject("objParcelableBean", objParcelableBean)
.withObject("objSerializableBean", objSerializableBean)
.withObject("normalTest", normalTest)
.navigation();
//目标界面
@Autowired(name = "objParcelableBean")
TestParcelableBean objParcelableBean;
@Autowired(name = "objSerializableBean")
TestSerializableBean objSerializableBean;
@Autowired(name = "normalTest")
NormalTest normalTest;
Log.e(TAG, objParcelableBean + "");
Log.e(TAG, objSerializableBean + "");
Log.e(TAG, normalTest + "");
我们发现用 Parcelable 序列化的对象为空,分析build的编译文件
@Override
public void inject(Object target) {
serializationService = ARouter.getInstance().navigation(SerializationService.class);
LoginActivity substitute = (LoginActivity)target;
substitute.objParcelableBean = substitute.getIntent().getParcelableExtra("objParcelableBean");
if (null != serializationService) {
substitute.objSerializableBean = serializationService.parseObject(substitute.getIntent().getStringExtra("objSerializableBean"), new com.alibaba.android.arouter.facade.model.TypeWrapper<TestSerializableBean>(){}.getType());
} else {
Log.e("ARouter::", "You want automatic inject the field 'objSerializableBean' in class 'LoginActivity' , then you should implement 'SerializationService' to support object auto inject!");
}
if (null != serializationService) {
substitute.normalTest = serializationService.parseObject(substitute.getIntent().getStringExtra("normalTest"), new com.alibaba.android.arouter.facade.model.TypeWrapper<NormalTest>(){}.getType());
} else {
Log.e("ARouter::", "You want automatic inject the field 'normalTest' in class 'LoginActivity' , then you should implement 'SerializationService' to support object auto inject!");
}
}
我们可以看到唯独通过 Parcelable 方式序列化的对象没有使用SerializationService进行解析,而是直接从Bundle去取,但我们并不是通过withParcelable方法去设置的值,因此取得的数据为null。
小结:因此,为了方便我们的操作,没有序列化和使用 Serializable 序列化的对象使用 withObject 方法传递,使用 Parcelable 方式序列化的对象则采用 withParcelable 方法进行传递。
带动画跳转
之前我们要带动画跳转,要用到overridePendingTransition(int anim_in,int anim_out);这里也有提供,但是有个大坑哦:
ARouter.getInstance().build(Constance.ACTIVITY_PATH_SIMPLE).withTransition(R.anim.alpha_activity_in, R.anim.alpha_activity_out)
//navigation里,一定要加上当前的Context,不然动画不起效
.navigation(MainActivity.this, 99);
同时ARouter也提供了新版动画,但是需要api>= 16才能使用,效果还是很酷炫的:
public class SomeClass {
private Button btn;
public void someMethod() {
if (Build.VERSION.SDK_INT >= 16) {
ActivityOptionsCompat compat = ActivityOptionsCompat.makeScaleUpAnimation(
btn,
btn.getWidth(),
btn.getHeight(),
0,
0
);
Postcard postcard = ARouter.getInstance()
.build(Constant.ACTIVITY_PATH_SIMPLE)
.withOptionsCompat(compat)
.build();
ARouter.getInstance().navigation(postcard);
} else {
ToastUtils.showToast("api < 16,不支持新版动画");
}
}
}
类似Activity里的startActivityForResult(Intent intent, int requestCode);
带requestCode跳转
也是在.navigation()里,只要带上requestCode就Ok了。然后onActivityResult和正常使用一样。
ARouter.getInstance().build(Constance.ACTIVITY_PATH_SIMPLE).navigation(Context context, int requestCode);
setResult返回界面,你没看错,就是这么复杂!
Postcard postcard = ARouter.getInstance().build(Constance.ACTIVITY_PATH_MAIN);
LogisticsCenter.completion(postcard);
Class<?> destination = postcard.getDestination();
Intent intent = new Intent(SimpleActivity.this, destination);
setResult(1, intent);
finish();
Fragment的使用
之间说了Activity和Fragment都需要用@Route标注加上path。 这里Fragment的使用和Activity一样,但唯一的区别是,Activity是跳转,而Fragment是实例化Fragmen的实例,如下:
//记得要强转一下,这里传值什么的和Activity的用法一样。
HomeFragment homeFragment = (HomeFragment)ARouter.getInstance().build(Constance.Fragment_PATH_SIMPLE).navigation();
拦截器的使用
我们先看一段拦截器的代码:
import com.alibaba.android.arouter.facade.Postcard;
import com.alibaba.android.arouter.facade.callback.InterceptorCallback;
import com.alibaba.android.arouter.facade.template.IInterceptor;
import android.content.Context;
import static com.example.yourpackage.Constant.ACTIVITY_PATH_SIMPLE;
import static com.example.yourpackage.LogUtils;
@Interceptor(priority = 1)
public class FirstInterceptor implements IInterceptor {
@Override
public void process(Postcard postcard, InterceptorCallback callback) {
if (postcard.getPath().equals(ACTIVITY_PATH_SIMPLE)) {
LogUtils.i("ARouter拦截器", "FirstInterceptor 开始拦截 ======");
}
callback.onContinue(postcard);
}
@Override
public void init(Context context) {
LogUtils.i("ARouter拦截器", "first init");
}
}
1、拦截器使用很奇特,只要在你代码里写上这个类,就起作用了。估计@Interceptor标注,apt帮我们干了不少事。
2、首先用@Interceptor标注,(priority = 1)优先级,越小,越先执行。
3、实现IInterceptor接口。实现2个方法:init(),process()。
4、init()方法,在项目启动时候首先执行,process()方法在Activity跳转时调用
5、如果我们要为拦截器加上一些帅选条件的话可以通过Postcard
6、注意,只要设置了拦截器,这里不调用callback.onContinue(postcard);就会卡在当前的拦截器内。当然跳转就卡在当前页面。
跳转时加监听,配合拦截器使用
直接上代码。在代码里注释
ARouter.getInstance()
.build(Constance.ACTIVITY_PATH_SIMPLE)
.navigation(MainActivity.this, new NavigationCallback() {
@Override
public void onFound(Postcard postcard) {
//路由目标被发现时调用(Activity执行跳转代码,第一个执行)
//group 为路径的组。如果不自定义,会默认成path的/x/y的x
//group 可以自定义,如:@Route(path = Constance.ACTIVITY_PATH_MAIN,group = Constance.GROUP_FIRST)
//当然自定义组之后,跳转的时候要带上组名。
String group = postcard.getGroup();
//path 为全路径@Route(path = Constance.ACTIVITY_PATH_MAIN)
String path = postcard.getPath();
LogUtils.i("ARouter拦截器", "onFound ------> group == " + group + " " + "path == " + path);
}
@Override
public void onArrival(Postcard postcard) {
//路由到达后调用(注意这里是所有拦截器执行完之后才会调用)
String group = postcard.getGroup();
String path = postcard.getPath();
LogUtils.i("ARouter拦截器", "onArrival ------> group == " + group + " " + "path == " + path);
}
@Override
public void onLost(Postcard postcard) {
//路由被丢失时调用
LogUtils.i("ARouter拦截器", "onLost");
}
@Override
public void onInterrupt(Postcard postcard) {
//路由被拦截时调用
LogUtils.i("ARouter拦截器", "onInterrupt");
}
});
oup == " + group + " " + "path == " + path);
}
@Override
public void onLost(Postcard postcard) {
//路由被丢失时调用
LogUtils.i("ARouter拦截器", "onLost");
}
@Override
public void onInterrupt(Postcard postcard) {
//路由被拦截时调用
LogUtils.i("ARouter拦截器", "onInterrupt");
}
});