项目模块化设计:单一 Activity + 分层架构 + Hilt

这一章我们聊点实在的。你想想看,一个项目如果堆在一起,后期维护就是噩梦。我个人习惯从一开始就做好模块化,至少把架构定死。说白了,就是三个核心问题:用几个 Activity?代码怎么分层?依赖怎么管?

为什么我坚持单一 Activity

我刚开始做 Android 时,喜欢一个页面一个 Activity。后来项目大了,跳转传参、回退栈管理、状态恢复……各种坑。尤其是 Compose 出现后,导航完全交给了 Navigation Compose,那还要多个 Activity 干嘛?

单一 Activity 的好处很明显:

  • 生命周期集中管理 —— 你只用关心 Application 和 Activity 的生命周期。
  • 模块间解耦 —— 每个页面只是一个 Composable,可以独立测试。
  • 状态恢复更简单 —— SavedStateHandle 在 ViewModel 里直接可用。
注意: 单一 Activity ≠ 单页面应用。每个页面仍然是独立的 Composable,通过 NavHost 切换。

分层架构:UI / Data / Domain

好,现在我们把代码切三块。这不是什么新概念,但真的管用。我见过很多新手把网络请求、数据库查询、UI 逻辑全塞在一个 ViewModel 里,后来改需求改到崩溃。分层就是强制你遵守“各司其职”。

层级 职责 典型类 依赖关系
UI Layer 展示数据、处理用户交互 Activity, Composable, ViewModel 依赖 Domain Layer
Domain Layer 业务逻辑、用例编排 UseCase, 纯 Kotlin 类 依赖 Data Layer(接口)
Data Layer 数据源实现(本地/远程) Repository, DAO, Retrofit 无上层依赖

这里有个关键点:Domain 层只依赖接口,不依赖具体实现。比如 UseCase 里用 Repository 接口,而不是 Room 的 DAO。这样以后切换数据源,只用改 Data 层,Domain 层完全不用动。

我的经验: 我曾经在一个项目中直接把 Retrofit 网络请求放进 UseCase,结果换接口时改了 20 多个文件。分层就是要做到“改了 Data 层,UI 层什么都不用改”。

Hilt 依赖注入:别让自己写工厂

依赖注入不是新鲜事,但很多新手嫌麻烦。我一开始也觉得“手动 new 不就得了”,直到项目大起来,构造参数变得越来越多,改一个参数要改 N 个地方。Hilt 就是帮我们自动做这件事。

引入 Hilt 只需三步:

  1. 在 build.gradle 添加 Hilt 插件和依赖。
  2. 在 Application 类上添加 @HiltAndroidApp。
  3. 在 Activity 上添加 @AndroidEntryPoint。

代码示例(Application):

@HiltAndroidApp
class MyApplication : Application()

Activity 中注入 ViewModel:

@AndroidEntryPoint
class MainActivity : ComponentActivity() {
    // Hilt 会自动提供 ViewModel
    private val viewModel: MyViewModel by viewModels()
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MyAppTheme {
                MyScreen(viewModel)
            }
        }
    }
}

ViewModel 需要标记 @HiltViewModel:

@HiltViewModel
class MyViewModel @Inject constructor(
    private val myUseCase: MyUseCase
) : ViewModel()

这样一来,UseCase 又是通过构造函数注入。只要在 Hilt Module 里告诉它怎么提供 Repository,整个链条就自动串起来了。

完整分层图:一眼看清依赖关系

下面这张图把咱们刚才说的三个层和 Hilt 连线画在一起。你可以看到各个模块怎么协作,Hilt 怎么把依赖从 Data 层注入到 Domain 层,再注入到 UI 层。

项目模块化分层架构 + Hilt 依赖注入 UI Layer Activity ViewModel Domain Layer UseCase(接口) Data Layer Repository Room DAO Hilt DI @Module / @Provides 虚线箭头表示 Hilt 自动注入依赖 实线箭头表示直接依赖

嗯,这张图应该能帮你理清思路。UI 层只依赖 Domain 层的接口(通过 ViewModel 引用 UseCase),Domain 层依赖 Data 层的接口(Repository),Data 层负责具体数据库实现。Hilt 像个幕后管家,告诉各模块“你需要什么,我给你”。

实践中的避坑指南

我刚才说分层依赖接口,但很多新手会直接在 Domain 层引入 Room 的注解。**千万别**。Domain 层应该是纯 Kotlin,不依赖任何 Android 框架。我曾经在一个项目里犯过这个错,导致 Domain 层没法做单元测试(因为需要运行在 Android 环境)。

总结一下本章核心: 单一 Activity + 三层架构(UI/Domain/Data)+ Hilt 注入。这三者配合好了,后期加功能、改数据源、换网络库,都只需要动一个模块。

另外,Hilt 的 Module 要记得加 @InstallIn(SingletonComponent::class)。我自己以前漏掉过,结果 Hilt 抱怨找不到依赖,排查了半天。

好,就到这吧。下节我们真正开始写 Room 的数据库和 DAO。