更多关于 Android 中的 Clean Architecture:包含 Cross-cutting 特性的示例
发布: (2025年12月4日 GMT+8 06:41)
3 min read
原文: Dev.to
Source: Dev.to
介绍
现在我们来讨论跨整个应用的特性——异常、对话框、全局事件等。这些特性相互依赖。
核心思想是为全局事件创建一个 单一真实来源 (SSOT),并在主模块中订阅它。Kotlin Flows 能帮助我们实现这一点,我们将使用为此场景设计的 SharedFlow。
要求
- 平台:仅 Android(不含 CMP/KMP)
- 项目:多模块
- 每个特性都有自己的页面
- 任意特性都可以发送触发器
- 各特性相互独立
结构
总体方案

Domain 模块
Domain 模块是独立的,包含核心契约:
interface GlobalRepository {
val eventFlow: SharedFlow
fun sendTrigger(trigger: Trigger)
}
enum class Trigger {
SOME_TRIGGER_1,
SOME_TRIGGER_2,
// …
}
enum class GlobalEvent {
SOME_EVENT_1,
SOME_EVENT_2,
// …
}
Domain‑shared 模块
该模块依赖 :domain:core,并提供发送触发器的实现和 DI:
interface SendTrigger {
operator fun invoke(trigger: Trigger) // or suspend fun if needed
}
class SendGlobalEventImpl @Inject constructor(
private val repository: GlobalRepository
) : SendTrigger {
override fun invoke(trigger: Trigger) = repository.sendTrigger(trigger)
}
Data 模块
使用 MutableSharedFlow 实现 GlobalRepository:
class GlobalRepositoryImpl @Inject constructor(
// injected entities such as dispatcher or scope if needed
) : GlobalRepository {
private val _eventFlow = MutableSharedFlow()
override val eventFlow = _eventFlow.asSharedFlow()
override fun sendTrigger(trigger: Trigger) {
when (trigger) {
// some logic
// example:
// someScope.launch { _eventFlow.emit(event) }
// other logic
}
}
// …
}
Flow 参数(replay、buffer 等)可根据具体情况进行调优。
App 与特性模块
- App 模块:直接从
:domain:core注入GlobalRepository,或暴露获取事件流的接口。 - 特性模块:从
:domain:shared注入SendTrigger。
特性模块的工作方式请参见上一篇文章。
小结
该方案遵循了之前文章的相同原则:
- 单一独立的
:domain:core,包含共享接口。 - Data 模块充当全局事件的 SSOT。
此模式与文章 Sharing data between ViewModels 中描述的类似,只是应用在更大范围。
警告: 示例仅适用于上述特定需求。它可能不适用于其他项目类型。请勿盲目复制。
感谢阅读!