Kotlin使用Koin DI注入子模块时如何实现跨模块双向数据收发
Koin跨模块多层Activity通信实现方案
方案一:Koin注入全局协程事件总线(最推荐,完全解耦)
适合跨多层Activity、需要双向通信的场景,完全不耦合各模块的业务逻辑,仅依赖Koin的单例注入能力即可实现。
实现步骤
- 首先在所有模块共同依赖的公共基础模块中,定义事件类型和事件总线接口:
// 跨模块通信事件定义,用密封类方便类型校验 sealed class AppCrossEvent { // Sub3发送给Main的结果事件 data class Sub3Result(val content: String) : AppCrossEvent() // Main回复给Sub3的响应事件 data class MainReply(val feedback: String) : AppCrossEvent() } // 事件总线接口 interface CrossModuleBus { // 发送事件 suspend fun send(event: AppCrossEvent) // 观察全局事件 fun observe(): Flow<AppCrossEvent> } // 事件总线实现类,用SharedFlow实现无内存泄漏的事件分发 class CrossModuleBusImpl : CrossModuleBus { private val eventFlow = MutableSharedFlow<AppCrossEvent>(extraBufferCapacity = 16) override suspend fun send(event: AppCrossEvent) = eventFlow.emit(event) override fun observe(): Flow<AppCrossEvent> = eventFlow.asSharedFlow() }
- 将事件总线作为单例注册到Koin的全局公共模块中,所有子模块都可以直接注入使用:
// Koin公共模块注册 val commonKoinModule = module { single<CrossModuleBus> { CrossModuleBusImpl() } }
- 在MainActivity中注入事件总线,监听Sub3发送的事件,处理完成后发送回复:
class MainActivity : AppCompatActivity() { // Koin注入事件总线 private val bus: CrossModuleBus by inject() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // ... 原有初始化逻辑 // 绑定生命周期监听事件,避免内存泄漏 lifecycleScope.launch { repeatOnLifecycle(Lifecycle.State.STARTED) { bus.observe().collect { event -> when(event) { is AppCrossEvent.Sub3Result -> { // 处理Sub3返回的结果 Log.d("Main", "收到Sub3数据:${event.content}") // 处理完成后回复Sub3 launch { bus.send(AppCrossEvent.MainReply("已收到你的数据,处理完成")) } } else -> {} } } } } } }
- 在SubActivity3中注入事件总线,发送结果同时监听Main的回复:
class SubActivity3 : AppCompatActivity() { private val bus: CrossModuleBus by inject() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // ... 原有初始化逻辑 // 需要向Main发送数据时调用 findViewById<Button>(R.id.submit_btn).setOnClickListener { lifecycleScope.launch { bus.send(AppCrossEvent.Sub3Result("这是Sub3的返回数据")) } } // 监听Main的回复 lifecycleScope.launch { repeatOnLifecycle(Lifecycle.State.STARTED) { bus.observe().collect { event -> when(event) { is AppCrossEvent.MainReply -> { // 处理Main的回复 Toast.makeText(this@SubActivity3, event.feedback, Toast.LENGTH_SHORT).show() } else -> {} } } } } } }
方案二:全局状态持有者(适合需要持久化状态的场景)
如果你的数据需要持久化存储,而非一次性事件,可以用Koin注入一个全局单例的状态持有者,用StateFlow存储共享状态,各模块注入后直接监听状态变化即可,实现逻辑和事件总线基本一致,区别是StateFlow会保留最新状态,新的观察者订阅后会直接收到最新值,适合状态类的共享场景。
方案三:Activity Result API透传(适合短链路简单场景)
如果你的链路较短、业务简单,可以用官方的Activity Result API逐层传递结果:Sub3设置结果返回给Sub2,Sub2再返回给Sub1,Sub1再返回给Main,Main的回复也要逐层向下传递。该方案的缺点是耦合度高,每层Activity都需要编写透传逻辑,链路修改时需要改动的代码多。
注意事项
- 公共的事件、接口定义必须放在所有模块共同依赖的基础公共模块中,避免出现跨模块依赖错误
- 事件/状态监听必须绑定组件的生命周期,使用
repeatOnLifecycle等API避免内存泄漏 - 事件类建议用密封类实现,方便类型判断,避免不同业务的事件互相干扰
内容的提问来源于stack exchange,提问作者iSofia
相关产品推荐
相关产品推荐

