在Android组件化开发中,模块间通信是一个关键问题。本文将介绍如何通过接口下沉的方式实现不同Module之间的松耦合通信,以提高代码的可维护性和可扩展性。
项目Module依赖结构
首先,让我们了解一下本文讨论的项目Module
依赖结构:
app
├── lib_ai_extend (依赖lib_canvas_render)
├── lib_filter (依赖lib_opengl_render)
├── lib_canvas_render (依赖lib_common)
├── lib_opengl_render (依赖lib_common)
└── lib_common (基础组件)
图形化依赖关系:
┌─────────┐
│ App │
└────┬────┘
┌────────────┴────────────┐
┌─────▼─────┐ ┌───────▼─────┐
│lib_filter │ │lib_ai_extend│
└─────┬─────┘ └───────┬─────┘
┌──────────▼───────────┐ ┌──────────▼────────────┐
│ lib_opengl_render │ │ lib_canvas_render │
└──────────┬───────────┘ └──────────┬────────────┘
│ │
└─────────┐ ┌────────────┘
┌────▼──▼─────┐
│ lib_common │
└─────────────┘
接口下沉实现通信的核心思想
接口下沉的核心思想是:将接口定义放在底层公共模块中,具体实现放在上层业务模块中。这样可以实现:
- 下层模块定义接口,上层模块实现接口
- 各模块通过接口而非具体实现类进行通信
- 避免循环依赖问题
实现步骤
1. 在lib_common
基础组件中定义接口
首先,在基础组件lib_common中定义各个功能模块的接口:
object ServiceFactory {
// lib_ai_extend的服务接口
interface LibAIExtendService {
fun LibAIExtendServiceMethod()
}
// lib_filter的服务接口
interface LibFilterService {
fun LibFilterServiceMethod()
}
interface RouterService {
// Fragment注册
fun registerFragment(path: String, fragmentClass: Class<out Fragment>)
// Fragment切换
fun routerFragment(fragmentManager: FragmentManager?, containerId: Int, path: String, bundle: Bundle? = null)
// 直接切换Fragment实例
fun replaceFragment(fragmentManager: FragmentManager?, containerId: Int, fragment: Fragment)
}
}
2. 在lib_common
基础组件创建服务管理器
在lib_common
模块中创建一个服务管理器,用于注册和获取各个模块的服务实现:
// 服务管理类,单例实现
class ServiceManager private constructor() : ServiceProvider {
companion object {
// 单例实例
@Volatile
private var instance: ServiceManager? = null
// 获取单例实例
fun getInstance(): ServiceManager {
return instance ?: synchronized(this) {
instance ?: ServiceManager().also { instance = it }
}
}
}
private val services = mutableMapOf<Class<*>, Any>()
override fun <T : Any> getService(serviceClass: Class<T>): T? {
return services[serviceClass] as? T?
}
override fun <T : Any> addService(serviceClass: Class<T>, implementation: T) {
if (services.containsKey(serviceClass)) {
throw IllegalArgumentException("Service ${serviceClass.simpleName} already registered.")
}
services[serviceClass] = implementation
}
override fun <T : Any> removeService(serviceClass: Class<T>) {
if (!services.containsKey(serviceClass)) {
throw IllegalArgumentException("Service ${serviceClass.simpleName} not registered.")
}
services.remove(serviceClass)
}
}
3. 在各业务组件中实现接口
在各个功能模块中实现lib_common
中定义的接口:
// 在lib_ai_extend业务组件中实现业务接口
class LibAIExtendServiceImpl : ServiceFactory.LibAIExtendService{
override fun LibAIExtendServiceMethod() {
Log.d("yang", "LibAIExtendServiceMethod")
}
}
// 在lib_filter业务组件中实现业务接口
class LibFilterServiceImpl : LibFilterService {
override fun LibFilterServiceMethod() {
Log.d("yang", "LibFilterServiceMethod")
}
}
// 在lib_common基础组件中实现路由接口
class RouterServiceImpl : RouterService {
// 日志TAG
private val TAG = "yang"
// 路由表映射
private val fragmentRouteMap = mutableMapOf<String, Class<out Fragment>>()
// 注册Fragment路由表
override fun registerFragment(path: String, fragmentClass: Class<out Fragment>) {
fragmentRouteMap[path] = fragmentClass
}
// 通过路径切换Fragment
override fun routerFragment(
fragmentManager: FragmentManager?,
containerId: Int,
path: String,
bundle: Bundle?
) {
val fragmentClass = fragmentRouteMap[path] ?: run {
Log.e(TAG, "No fragment found for path: $path")
return
}
try {
val fragment = fragmentClass.getDeclaredConstructor().newInstance()
bundle?.let { fragment.arguments = it }
replaceFragment(fragmentManager, containerId, fragment)
} catch (e: Exception) {
Log.e(TAG, "Failed to instantiate fragment for path: $path", e)
}
}
override fun replaceFragment(
fragmentManager: FragmentManager?,
containerId: Int,
fragment: Fragment
) {
Log.e("yang", "replaceFragment containerId: $containerId, fragment : ${fragment::class.java.simpleName}")
val transaction = fragmentManager?.beginTransaction()
transaction?.replace(containerId, fragment)
transaction?.commitAllowingStateLoss()
}
}
4. 在壳App模块中初始化服务
在App
模块的Application
类中初始化并注册各个服务:
class MainApp : Application(){
override fun onCreate() {
super.onCreate()
initRouterService()
initFilterModule()
initAIExtendModule()
}
}
fun initFilterModule(){
ServiceManager.getInstance().addService(LibFilterService::class.java, LibFilterServiceImpl())
ServiceManager.getInstance().getService(RouterService::class.java)?.apply {
registerFragment(RouterPath.FRAGMENT_FILTER, FilterFragment::class.java)
}
}
fun initAIExtendModule(){
ServiceManager.getInstance().addService(LibAIExtendService::class.java, LibAIExtendServiceImpl())
}
fun initRouterService(){
ServiceManager.getInstance().addService(RouterService::class.java, RouterServiceImpl())
}
5. 壳App模块和没有依赖关系的业务模块,进行页面跳转和方法调用
// 页面跳转,通过路由服务跳转注册过的Fragment
val routerServiceImpl = ServiceManager.getInstance().getService(RouterService::class.java)
class RouterServiceImpl : RouterService {
// 日志TAG
private val TAG = "yang"
// 路由表映射
private val fragmentRouteMap = mutableMapOf<String, Class<out Fragment>>()
// 注册Fragment路由表
override fun registerFragment(path: String, fragmentClass: Class<out Fragment>) {
fragmentRouteMap[path] = fragmentClass
}
// 通过路径切换Fragment
override fun routerFragment(
fragmentManager: FragmentManager?,
containerId: Int,
path: String,
bundle: Bundle?
) {
val fragmentClass = fragmentRouteMap[path] ?: run {
Log.e(TAG, "No fragment found for path: $path")
return
}
try {
val fragment = fragmentClass.getDeclaredConstructor().newInstance()
bundle?.let { fragment.arguments = it }
replaceFragment(fragmentManager, containerId, fragment)
} catch (e: Exception) {
Log.e(TAG, "Failed to instantiate fragment for path: $path", e)
}
}
override fun replaceFragment(
fragmentManager: FragmentManager?,
containerId: Int,
fragment: Fragment
) {
Log.e("yang", "replaceFragment containerId: $containerId, fragment : ${fragment::class.java.simpleName}")
val transaction = fragmentManager?.beginTransaction()
transaction?.replace(containerId, fragment)
transaction?.commitAllowingStateLoss()
}
}
// 方法调用,通过业务服务实现类,调用业务组件暴露的方法
ServiceManager.getInstance().getService(ServiceFactory.LibAIExtendService::class.java)?.apply {
LibAIExtendServiceMethod()
}
ServiceManager.getInstance().getService(ServiceFactory.LibFilterService::class.java)?.apply {
LibFilterServiceMethod()
}
接口下沉实现的优势
- 解耦合:上层模块只依赖接口,不依赖具体实现,降低了模块间的耦合度
- 避免循环依赖:通过将接口下沉到公共模块,避免了模块间的循环依赖问题
- 灵活替换:可以轻松替换模块的具体实现,而不影响其他模块
- 便于测试:可以轻松模拟接口实现,便于单元测试
- 并行开发:不同团队可以并行开发不同模块,只需遵循接口约定
注意事项 - 接口设计要稳定:接口一旦定义,变更成本较高,需要谨慎设计
- 避免接口爆炸:不要为每个小功能都定义接口,应该按照业务领域合理划分
- 初始化顺序:要注意服务注册和使用的顺序,确保在使用前已完成注册
- 考虑懒加载:对于不常用的服务,可以考虑懒加载方式,减少启动时间
- 错误处理:服务获取失败时需要有合理的错误处理机制
总结
接口下沉是Android组件化架构中实现模块间通信的有效方式。通过在公共基础模块中定义接口,在上层模块中实现接口,并使用服务管理器进行统一管理,可以实现模块间的松耦合通信,提高代码的可维护性和可扩展性。