You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin使用Koin DI注入子模块时如何实现跨模块双向数据收发

Koin跨模块多层Activity通信实现方案

方案一:Koin注入全局协程事件总线(最推荐,完全解耦)

适合跨多层Activity、需要双向通信的场景,完全不耦合各模块的业务逻辑,仅依赖Koin的单例注入能力即可实现。

实现步骤

  1. 首先在所有模块共同依赖的公共基础模块中,定义事件类型和事件总线接口:
// 跨模块通信事件定义,用密封类方便类型校验
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()
}
  1. 将事件总线作为单例注册到Koin的全局公共模块中,所有子模块都可以直接注入使用:
// Koin公共模块注册
val commonKoinModule = module {
    single<CrossModuleBus> { CrossModuleBusImpl() }
}
  1. 在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 -> {}
                    }
                }
            }
        }
    }
}
  1. 在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.11 07:09:01