组件,就是对数据和方法的简单封装,功能单一,高类聚,是业务划分的最小粒度。组件化是基于可重用的目的,将大型软件系统按照分离关注点的形式,拆分成多个独立组件,使得整个软件是单个或多个组件元件组装起来。那组件之间如何通信呢?这就得益于ARouter。
Android原生的路由方案是Intent的显式和隐式跳转,显式需要对目标的引用,会导致不同页面的耦合,隐式集中配置在manifest中,不利于维护和管理。况且,在组件化开发中,各模块之间无法直接引用,那么,ARouter路由框架就派上用场了。
一个用于帮助 Android App 进行组件化改造的框架 —— 支持模块间的路由、通信、解耦
原理简述
ARouter通过APT技术,生成保存路径(路由path)和被注解(@Router)的组件类的映射关系的类,利用这些保存了映射关系的类,根据用户的请求postcard寻找到要跳转的目标地址,使用Intent跳转。所以,该框架的核心是利用APT生成的映射关系,APT的作用是在编译阶段扫描并处理代码中的注解,然后根据注解输出Java文件。
基本使用
添加依赖和配置,注意,每个使用到ARouter的Module都要引入
plugins {
id 'com.android.library'
id 'org.jetbrains.kotlin.android'
id 'kotlin-kapt'
}
kapt {
arguments {
arg("AROUTER_MODULE_NAME", project.getName())
}
}
implementation 'com.alibaba:arouter-api:1.5.2'
kapt 'com.alibaba:arouter-compiler:1.5.2'
引入后需要注意的一点是:要在gradle.properties文件中加入下面这个,不然会编译不过去,这也是我遇到的一个小坑。
android.enableJetifier=true
在Application中初始化
if (isDebug()) {
ARouter.openLog()
ARouter.openDebug()
}
ARouter.init(this)
在支持路由的页面上添加如下注解,路径至少需要两级
@Route(path = "/home/HomeActivity")
class HomeActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_home)
}
}
然后在另一个Activity中,进行跳转
ARouter.getInstance().build("/home/HomeActivity").navigation()
如果需要传递参数的话,可以这样做
ARouter.getInstance().build("/home/HomeActivity")
.withString("name", "Uncle Xing")
.withInt("age", 25)
.withSerializable("user", User("Uncle Xing", 25))
.navigation()
然后在目标Activity中通过Autowired接收,ARouter会自动对字段进行赋值,无需主动获取
@Route(path = "/home/HomeActivity")
class HomeActivity : AppCompatActivity() {
@JvmField
@Autowired
var name = ""
@JvmField
@Autowired
var age = 0
@JvmField
@Autowired
var user: User? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_home)
initView()
}
private fun initView() {
ARouter.getInstance().inject(this)
findViewById<TextView>(R.id.name).text = name
findViewById<TextView>(R.id.age).text = age.toString()
findViewById<TextView>(R.id.user).text = user.toString()
}
}
在组件化开发中,我们通常会有一些公共Module来作为共有功能,那这个时候就可以使用ARouter的依赖注入解耦,组件件的通信,首先我们要声明接口,其他组件通过这个接口来调用方法
interface MyProvider : IProvider {
fun getData(): String
}
实现类
@Route(path = "/common/MyProviderImpl")
class MyProviderImpl : MyProvider {
override fun getData(): String {
return "Welcome to my blog"
}
override fun init(context: Context?) {
}
}
其他组件的Activity就可以这样调用
class MainActivity : AppCompatActivity() {
@JvmField
@Autowired(name = "/common/MyProviderImpl")
var myProvider: MyProvider? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
initView()
}
private fun initView() {
ARouter.getInstance().inject(this)
findViewById<TextView>(R.id.provider_text).text = myProvider?.getData()
}
}
上面是使用依赖注入的方式,通过注解标注字段,即可使用,无需主动获取,除此之外,我们也可以使用赖查找的方式,比如上面的代码我们也可以写成这样
class MainActivity : AppCompatActivity() {
var myProvider: MyProvider? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
initView()
}
private fun initView() {
myProvider =
ARouter.getInstance().build("/common/MyProviderImpl").navigation() as MyProvider
findViewById<TextView>(R.id.provider_text).text = myProvider?.getData()
}
}
我们也可以动态注册路由,这样,目标页面和服务就可以不标注 @Route 注解。不过,一般组件化项目都不会这样干,适合部分插件化架构的项目或其他场景。
ARouter.getInstance().addRouteGroup {
it["/home/HomeActivity"] = RouteMeta.build(
RouteType.ACTIVITY,
HomeActivity::class.java,
"/home/HomeActivity",
"home",
0, 0
)
}
注意:同一批次仅允许相同 group 的路由信息注册
|