前言:路由可以说是模块化开发必备技能了,它可以很方便实现模块之间页面跳转,传参等等操作,而且管理起来也方便,在我们实际开发中页面直接跳转可能不仅仅 从A跳转到B那么简单,比如我从A页面跳转到B页面需要判断用户是否登录了,如果没有登录就跳转到登录页面.那么此时路由的拦截就发挥作用了,在此之前我们可能都是在每个页面的setContentView之前进行判断,这样代码重复量以及可读性,维护性都不强。今天就简单给大家介绍下Arouter路由(阿里路由)
1.Arouter路由集成(kt篇,如果是java开发请自行参考GitHub - alibaba/ARouter: 💪 A framework for assisting in the renovation of Android componentization (帮助 Android App 进行组件化改造的路由框架)文档)
(1)在gradle里面配置moudle-name,
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
kapt {
arguments {
arg("AROUTER_MODULE_NAME", project.getName())
}
}
其中AROUTER_MODULE_NAME只是一个key值可以自行命名.
(2)添加Arouter相关依赖
api 'com.alibaba:arouter-api:1.5.0' kapt 'com.alibaba:arouter-compiler:1.2.2'
添加依赖需要注意的是:如果模块之间依赖了,那么主模块添加上面两个,然后子模块添加kapt 'com.alibaba:arouter-compiler:1.2.2'这个就行。但是需要注意的是必须每个模块都保证有这两个依赖。而且都要配置moudlename
到此Arouter一些基础配置就差不多了,后面就直接可以用到项目里面了.总体来说配置都不难,只是需要注意是kt还是java开发,然后保证每个模块都有配置moudle-name以及依赖api 'com.alibaba:arouter-api:1.5.0' ,kapt 'com.alibaba:arouter-compiler:1.2.2'
(3)Arouter基础使用:
我在这里就直接说出我个人使用Arouter跳转及传参方法了,每个人使用方法也不一样,可自行参考,择优!
1.配置路由表:
class ARouterPath {
companion object {
//登录
const val LOGIN_PATH = "/user/view/activity/LoginActivity"
//主页面
const val MAIN_PATH = "/healthcdxt/view/activity/MainActivity"
}
这里配置了两个路由表,一个主页面一个登陆页面,现在我们需要从主页面跳转到登录页面。
2.创建activity添加注解
@Route(path = ARouterPath.MAIN_PATH)
class MainActivity : BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
initTab()
}
}
@Route(path = ARouterPath.LOGIN_PATH)
class LoginActivity : BaseActivity(){
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_login)
}
在使用Arouter跳转的activity都需要添加Route注解,然后利用path来配置当前activity的路由即我们在第一步配置的路径,比如:
ARouterPath.LOGIN_PATH就是登录页面配置的路由,ARouterPath.MAIN_PATH就是主页面配置的路由。在配置路由的时候需要注意路由的路径至少2级目录以上,最好配置成------------------/模块名/包名/类名。Ok,路由表以及路由都配置好了,那么接下来就是利用路由进行跳转了。
3.路由跳转和传值
1.简单的跳转不传值:
ARouter.getInstance().build(ARouterPath.LOGIN_PATH)
.navigation()
Arouter类查看源码便知是由单列生成的
public static ARouter getInstance() {
if (!hasInit) {
throw new InitException("ARouter::Init::Invoke init(context) first!");
} else {
if (instance == null) {
synchronized (ARouter.class) {
if (instance == null) {
instance = new ARouter();
}
}
}
return instance;
}
}
然后build传的就是在路由表配置的路径, const val LOGIN_PATH = "/user/view/activity/LoginActivity"。这个路径表示你要跳转的页面。后面的navigation可以拿到相应的对象。在这里就不过多阐述.此外还可以在跳转时添加跳转动画:
ARouter.getInstance().build(ARouterPath.LOGIN_PATH)
.withTransition(R.anim.slide_right_in, R.anim.slide_left_out)
.navigation(mActivity)
添加动画直接调用withTransition方法,具体动画实现就看各自需求了。
2.跳转时传值
(1)传值:
ARouter.getInstance().build(ARouterPath.LOGIN_PATH)
.withString("topath", "tologin")
.navigation()
传值也很方便直接跳转Arouter里面的withxxx方法。比如上面我传一个字符串直接调用.withString("topath", "tologin"),其中第一个参数key,第二个为对应的value。需要注意的是:这里的key必须与接收方保持一致.如果需要传其他类型值,也是同样方式,参考下图传就可以满足你的需求了。

(2)接收值( Arouter传值中接收值才是重点也是特别需要注意的点),我这里是用kt,如果是java请另行参考.
1.在写项目时如果你知道这个页面需要接收值。那么第一步就是在页面onCreate中添加Arouter注入
ARouter.getInstance().inject(this)
这一步是接收值的关键的一步。不然很有可能你接收不到值。
2.定义接收值:回到上面说到的传值withString("topath", "tologin"),其中的topath就是key,那么我们在接收值的时候定义的变量一定要与其保持一致,接收方定义如下:
@Autowired @JvmField var topath: String? = null
当然你也可以
@Autowired(name="topath") @JvmField var topath: String? = null
特别提醒:在kt中接收值是这样,在java中就不一样。这里我就不贴java相关的了,ok,页面跳转以及传值到此就差不多了。下面就说下Arouter拦截器,这也是我们在项目中必不可少的。而且使用也是非常方便,简单.
4.Arouter实现路由拦截
(1)拦截定义:何为拦截?我想从A页面跳转到B页面,此时我要拦截你的跳转不让你从A到B,fuck,那么我就从A到C再到B.差不多这就是拦截的意义.
(2)自定义拦截器:既然我们要实现路由拦截,那么什么情况拦截,拦截后需要搞什么梗?这个都需要我们自己去定义,首先看下自定义拦截器.它的定义标识了你的路由跳转什么时候拦截,什么时候不拦截。
@Interceptor(priority = 8, name = "登录拦截器")
class MyInterceptor : IInterceptor{
var mContext: Context? = null
override fun process(postcard: Postcard?, callback: InterceptorCallback?) {
//如果有extras值就不拦截
if (ConfigParam.NOINTERCEPTOR == postcard!!.extras!!.getString(ConfigParam.NOINTERCEPTOR)) {
callback!!.onContinue(postcard)
} else {
//这是我项目中用到的路由,需要换成你自己的
when (postcard!!.path) {
ARouterPath.STARTUP_PATH, ARouterPath.LOGIN_PATH, ARouterPath.REGISTER_PATH, ARouterPath.MAIN_PATH, ARouterPath.RESETTING_PASSWORD,
ARouterPath.GESTUREPASSWORD_LOGIN, ARouterPath.CODE_LOGIN, ARouterPath.UNREGISTERED_PATH,
ARouterPath.SUPPORT_PATH, ARouterPath.SYSTEM_INTRODUCE, ARouterPath.DOWNAPPURL
-> {
//不拦截
callback!!.onContinue(postcard)
}
else -> {
//如果需要登录
if (!Helper.getSharedPreferences(mContext!!).getBoolean(
ConfigParam.IS_LOGIN,
true
) ||
Helper.getSharedPreferences(mContext!!).getBoolean(
ConfigParam.OVER_TIME,
true
)
)
//拦截
{
callback!!.onInterrupt(null)
} else {
//不拦截
callback!!.onContinue(postcard)
}
}
}
}
}
override fun init(context: Context?) {
mContext = context
}
}
OMG,这么多判断,什么拦截,什么不拦截,仿佛一看当场晕倒...骚年先来一根烟压压惊稳住..........
其实里面的逻辑并不难,我先把拦截流程讲完,再给大家说下这里拦截的逻辑.
定义好了拦截器,就是怎么在路由跳转进行拦截了。这就简单了。
ARouter.getInstance().build(ARouterPath.ORDER_MANAGER)
.withTransition(R.anim.slide_right_in, R.anim.slide_left_out)
.navigation(mActivity, MyNavigationCallback())
假如我要从主页面跳转到路由表对应的ARouterPath.ORDER_MANAGER页面,但是我需要拦截此次路由跳转,直接在navigation里面加上一个NavigationCallback接口实现类.我们看下MyNavigationCallback源码
inner class MyNavigationCallback : NavigationCallback {
override fun onLost(postcard: Postcard?) {
}
override fun onFound(postcard: Postcard?) {
}
override fun onInterrupt(postcard: Postcard?) {
Log.e("onInterrupt", "onInterrupt")
Log.e("currentThread", Thread.currentThread().name)
mActivity.runOnUiThread {
Log.e("currentThread22", Thread.currentThread().name)
ARouter.getInstance().build(ARouterPath.LOGIN_PATH)
.withString("topath", postcard!!.path)
.navigation()
}
}
override fun onArrival(postcard: Postcard?) {
Log.e("onArrival", "onArrival")
}
}
这个类实现了四个方法,onFound表示拦截之前调用,onInterrupt拦截时调用,onArrival跳转到目的页面后调用。一般我们只用到这个三个方法。上面说到要从主页面跳转到ARouterPath.ORDER_MANAGER页面,但是此时我需要判断是否登录,如果没有登录需要拦截,拦截onInterrupt跳转到登录页面,可以看到跳转到登录页面传了一个path值,这个值就是ARouterPath.ORDER_MANAGER路由,当跳转到登录页面用户登录后,就直接跳转到ARouterPath.ORDER_MANAGER页面了,一套简单的路由拦截就差不多了。
梳理一下:定义拦截器,然后路由跳转时实现NavigationCallback接口,在拦截方法中添加自己的拦截目的。
接下来说下自定义拦截器和NavigationCallback逻辑:
先给大家模拟两个场景:1.我需要A页面跳转到B但是需要判断是否登录,如果没有登录就跳转到C。(这个场景就是文章中的)
2.结合场景一,假如我在A页面中点击某个菜单进入页面B,此时需要判断是否登录,没有就先跳转到登录页面C。但是此时我又是新用户需要注册,需要从C进入注册页面D,在注册页面D中添加用户信息我需要进入页面B。前面我们对B路由进行拦截了,此时我们从D跳转到B是不是又重新回到登录页面C了?自始至终都无法从D进入B。
场景模拟完了,看代码逻辑怎么处理这两种场景
@Interceptor(priority = 8, name = "登录拦截器")
class MyInterceptor : IInterceptor{
}
首先自定义拦截器要实现IInterceptor接口,并添加Interceptor注解.注解中priority线程优先级别,nam就是一个标识。如果你有多个拦截器两个值不能一致.唯一注意的就是priority值越小优先级越高.
IInterceptor接口有两个方法。一个init一个process.init在编译的时候就执行了,也就是MyInterceptor 类加载的时候。在as编译的时候检测到MyInterceptor 会自动生成一个拦截器相关的类。然后就是process方法。这个方法就是我们自定义拦截器逻辑实现重点了。不过需要注意的是这个方法是在子线程执行的。我们先看下面的逻辑(代码细节问题请忽略)
//如果有extras值就不拦截
if (ConfigParam.NOINTERCEPTOR == postcard!!.extras!!.getString(ConfigParam.NOINTERCEPTOR)) {
callback!!.onContinue(postcard)
} else {
when (postcard!!.path) {
ARouterPath.STARTUP_PATH, ARouterPath.LOGIN_PATH, ARouterPath.REGISTER_PATH, ARouterPath.MAIN_PATH, ARouterPath.RESETTING_PASSWORD,
ARouterPath.GESTUREPASSWORD_LOGIN, ARouterPath.CODE_LOGIN, ARouterPath.UNREGISTERED_PATH,
ARouterPath.SUPPORT_PATH, ARouterPath.SYSTEM_INTRODUCE, ARouterPath.DOWNAPPURL
-> {
//不拦截
callback!!.onContinue(postcard)
}
else -> {
//如果需要登录
if (!Helper.getSharedPreferences(mContext!!).getBoolean(
ConfigParam.IS_LOGIN,
true
) ||
Helper.getSharedPreferences(mContext!!).getBoolean(
ConfigParam.OVER_TIME,
true
)
)
//拦截
{
callback!!.onInterrupt(null)
} else {
callback!!.onContinue(postcard)
}
}
}
}
先看
这部分代码。先用postcard.path拿到想跳转的页面路由。我们项目中并不是所有页面都需要判断登录,因此在
我们添加不需要判断登录的页面路由,调用 callback!!.onContinue(postcard)。onContinue顾名思义就是继续你的操作,我不拦截你了。那么不是上面的路由跳转就需要判断是否登录了,
怎么判断是否登录这个需要根据自己项目需求来判定。如果需要登录就callback!!.onInterrupt(postcard),onInterrupt顾名思义就是拦截,如果不需要登录就callback!!.onContinue(postcard)不拦截。如果拦截了,怎么做?我们再来看下MyNavigationCallback源码
inner class MyNavigationCallback : NavigationCallback {
override fun onLost(postcard: Postcard?) {
}
override fun onFound(postcard: Postcard?) {
}
override fun onInterrupt(postcard: Postcard?) {
Log.e("onInterrupt", "onInterrupt")
Log.e("currentThread", Thread.currentThread().name)
mActivity.runOnUiThread {
Log.e("currentThread22", Thread.currentThread().name)
ARouter.getInstance().build(ARouterPath.LOGIN_PATH)
.withString("topath", postcard!!.path)
.navigation()
}
}
override fun onArrival(postcard: Postcard?) {
Log.e("onArrival", "onArrival")
}
}
需要注意onInterrupt也是在子线程中执行的。onInterrupt里面跳转我就不再说了上面已经说得很详细,再说下onFound,onArrival。onFound方法是在拦截之前执行的,而onArrival是到达目的页面后执行.在这两个方法中根据实际情况做操作.
我们回到MyInterceptor 中。还剩下extras不拦截。这个又是什么梗?又回到我们模拟的场景2.假如我们在D跳转到B页面传递一个值,这个值标识不管登录与否都不需要拦截。
然后在跳转时传一个
ConfigParam.NOINTERCEPTOR, ConfigParam.NOINTERCEPTOR

当跳转的时候拦截器检查到这个值根据自定义拦截器,我们对此次路由跳转不拦截,那么我们就完美解决场景2的问题了。
此次路由跳转,传值,拦截就告一段落了,文章可能重复的内容比较多,但是根据思路来应该差不多能收货不少。
最后祝各位.工作愉快,健健康康。顺便贴上群里290611780,欢迎各位勇士加入!!!
更新时间:2023-11-27 取消拦截器继承baseactivity,否则会导致拦截问题
本文详细介绍阿里Arouter路由框架的集成与使用,包括配置路由表、注解使用、跳转传值、路由拦截等核心功能,适合Android开发者快速掌握模块化开发必备技能。
499





