组件间通信的实现方式,最为著名的莫过于阿里的ARouter框架。但是除此之外,笔者认为,还有一种原生的通信方式可以在大多数项目架构中使用。
能应用这种通信方式的项目,其架构的底层必须包含一个且仅有一个基础功能模块,将其称之为Root模块。该模块集成网络,存储,Json解析等最基础、通用的底层功能,而项目中其他的业务层模块均依赖于该模块。
事实上,大多数基于组件化的Android项目均为该体系架构。本文以该架构为前提,介绍该架构下组件间通信的一种方式。
为了方便描述,将各个业务模块称为A模块、B模块、C模块,基础模块称为Root模块。
首先,为了实现解耦,即业务与通信分离的目的,各个业务模块均需要配套一个对外服务模块_external。
以A为例,外部模块A_external负责向其他业务模块(B、C)暴露与业务模块A通信的接口,而接口的具体实现由业务模块A在内部完成。
// Module A_external:
interface ExposedServices_A {
fun getPaymentActivity(context: Context): Intent
fun getShoppingActivity(context: Context): Intent
//...
}
// Module A:
class ExposedServicesImpl_A : ExportedServices_A {
override fun getPaymentActivity(context: Context): Intent {
return PaymentActivity.createIntent(context)
}
override fun getShoppingActivity(context: Context): Intent {
return ShoppingActivity.createIntent(context)
}
//...
}
理所当然,业务模块A持有对外部模块A_external的依赖。
Root模块包含一个单例类,类中维护一个私有的HashMap< String, InterfaceImpl >实例,并向外暴露register()和get()方法。register()由A初始化时调用,将类和接口实现绑定。其他模块通过get()方法获取接口实现类。
class ModuleServiceLoader private constructor() {
companion object {
// 单例
val instance by lazy { ModuleServiceLoader() }
}
// 维护[external模块中对外暴露的接口名]与[内部模块接口实现类]的绑定
private val serviceMap: HashMap = HashMap()
// 模块初始化时调用
fun register(apiClass: Class, apiImpl: T) {
serviceMap[apiClass.name] = apiImpl
}
// 模块调用get拿到其他模块的apiImpl,达到通信的目的
fun get(apiClass: Class): T? {
return serviceMap[apiClass.name] as? T
}
}
该服务类为单例类,因为它并未持有其他业务模块Activity的引用,而是业务模块初始化时将className这个字符串传给它。
例如:
// Application启动时,模块A初始化
ModuleServiceLoader.instance.register(
ExposedServices_A::class.java,
ExposedServicesImpl_A
)
其他模块访问A模块:
// B模块调用A模块方法
val service = ModuleServiceLoader.instance.get(
ExposedServices_A::class.java
)
service.startActivity(service.getPaymentActivity)
这种方式本质上是巧妙地利用各业务模块A, B, C对Root模块的共同依赖关系。以此,实现了模块间通信。



