标准 Android 项目结构(MVVM + 分层架构)

你这个情况非常常见,尤其是刚接触 Android 或 Jetpack Compose 的时候。下面我用一个结构清晰、职责分明的项目分层指南来帮你理一理,解决“写哪都不对”的问题。


✅ 标准 Android 项目结构(MVVM + 分层架构)

com.example.app
│
├── data/                 // 数据层:数据源、网络、数据库、模型
│   ├── model/            // 数据模型(如 User.kt, UpdateInfo.kt)
│   ├── network/          // Retrofit 接口定义、API请求
│   └── repository/       // 仓库层:组合调用多个数据源
│
├── domain/               // 领域层(可选):业务逻辑、用例(UseCase)
│   └── usecase/          // eg: CheckUpdateUseCase.kt
│
├── ui/                   // 展示层:Activity、Fragment、Compose、ViewModel
│   ├── screen/           // 各个页面模块
│   │   ├── home/
│   │   │   ├── HomeScreen.kt
│   │   │   └── HomeViewModel.kt
│   │   └── update/
│   │       ├── UpdateScreen.kt
│   │       └── UpdateViewModel.kt
│   └── component/        // 公共组件,如 Button、Card、Dialog 封装
│
├── utils/                // 工具类,如 UpdateUtils.kt、DateUtils.kt
│
└── MainActivity.kt       // 入口,通常作为导航容器

👇 各层该写什么?

位置 职责说明
model/ 定义数据结构(如从服务器拿到的 JSON 对象)
network/ Retrofit 接口、HTTP 请求封装
repository/ 管理数据来源(比如先从缓存拿,没有再请求)
usecase/(可选) 把多个 Repository 操作组合起来形成“某个业务逻辑”
viewmodel/ 页面状态、调业务逻辑(usecase 或 repository),暴露状态给 UI
ui/ 展示界面(Compose),收集状态、响应事件
utils/ 非依赖上下文的工具函数,适合封装成 object
MainActivity.kt 只做导航容器或顶层初始化

✅ 举个例子:检查更新功能应该怎么分

✔️ 1. model/UpdateInfo.kt

data class UpdateInfo(
    val latestVersion: String,
    val releaseNote: String,
    val downloadUrl: String
)

✔️ 2. network/UpdateApi.kt

interface UpdateApi {
    @GET("releases/latest")
    suspend fun getLatestRelease(): Response<UpdateInfo>
}

✔️ 3. repository/UpdateRepository.kt

class UpdateRepository(private val api: UpdateApi) {
    suspend fun fetchUpdate(): UpdateInfo {
        return api.getLatestRelease().body()!!
    }
}

✔️ 4. viewmodel/UpdateViewModel.kt

class UpdateViewModel(private val repo: UpdateRepository) : ViewModel() {
    var updateInfo by mutableStateOf<UpdateInfo?>(null)
        private set

    var isLoading by mutableStateOf(false)

    fun checkForUpdate() {
        viewModelScope.launch {
            isLoading = true
            updateInfo = repo.fetchUpdate()
            isLoading = false
        }
    }
}

✔️ 5. screen/update/UpdateScreen.kt

@Composable
fun UpdateScreen(vm: UpdateViewModel) {
    val info = vm.updateInfo
    val loading = vm.isLoading

    Button(
        onClick = { vm.checkForUpdate() },
        enabled = !loading
    ) {
        if (loading) {
            CircularProgressIndicator()
        } else {
            Text("检查更新")
        }
    }

    info?.let {
        Text("最新版本:${it.latestVersion}")
    }
}

✳️ 提示:如何开始重构?

  1. 从现有功能拆分出 ViewModel
  2. 再拆出 Repository 和网络部分
  3. 最后整理 model 和 utils 目录

想让结构清晰,记住一句话:

UI 不做逻辑,逻辑不操作网络,网络不关心 UI。


如果你愿意,我可以:

  • 帮你一步步重构当前项目结构
  • 或者基于你现有功能,帮你生成一套清晰结构模板

你更希望我现在从哪块开始帮你整理?(比如检查更新功能、登录、首页等)

posted @ 2025-05-05 23:54  ShengOasis  阅读(264)  评论(0)    收藏  举报