用一个小 Demo,带你入门安卓 Clean Architecture

675 阅读4分钟

前言:为什么你的代码越来越难维护?

你是否遇到过这些问题:

  • 业务逻辑直接写在 Activity / Fragment
  • UI、网络、数据库代码混在一起,牵一发而动全身
  • 一个接口字段改动,整个项目到处报错
  • 想写单元测试,却发现严重依赖 Android Framework

如果你对以上情况并不陌生,那么问题往往不是你写得不够努力,而是项目缺乏清晰的架构设计

Clean Architecture(整洁架构),正是为了解决这些问题而提出的一种架构思想。


什么是 Clean Architecture?

Clean Architecture 不是一个框架,而是一种设计原则。

它的核心目标可以总结为一句话:

让核心业务逻辑独立于 UI、框架和实现细节。

也就是说:

  • UI 可以随意更换(XML → Compose)
  • 网络库可以替换(Retrofit → Ktor)
  • 数据来源可以变化(API → 本地数据库)

👉 但业务逻辑几乎不用改动。

核心原则:依赖倒置(Dependency Rule)

Clean Architecture 最重要的一条规则是:

代码的依赖方向,只能从外层指向内层。

  • 内层:业务规则(最稳定)
  • 外层:UI、网络、数据库(最容易变化)

📌 内层永远不知道外层的存在


Clean Architecture 的分层结构

在 Android 项目中,Clean Architecture 通常可以拆分为三层:

1️⃣ Presentation(表现层)

职责:负责 UI 展示和用户交互

常见组件:

  • Activity / Fragment
  • Jetpack Compose
  • ViewModel

特点:

  • 不包含业务规则
  • 只负责管理 UI State
  • 通过 UseCase 调用业务逻辑

2️⃣ Domain(领域层)⭐ 核心层

职责:定义业务规则和业务模型

包含内容:

  • Entity / Model
  • UseCase
  • Repository 接口(抽象)

特点:

  • 纯 Kotlin
  • 不依赖 Android
  • 不依赖任何第三方库
  • 是整个项目中最稳定的一层

📌 这一层承载了项目真正的“业务价值”。


3️⃣ Data(数据层)

职责:负责数据从哪里来、如何获取

包含内容:

  • 网络请求(API)
  • 本地数据库
  • Repository 的具体实现

特点:

  • 实现 Domain 层定义的接口
  • 可以自由切换数据来源
  • 是变化最频繁的一层

CleanArc 项目实践

接下来,我们通过一个简单的示例项目 CleanArc,来看看 Clean Architecture 在真实 Android 项目中是如何落地的。

🎯 项目目标很简单:

从服务器获取用户列表,并将其展示在界面上


Data 层:数据的来源(How)

Data 层只关心一件事:

我如何把数据拿到?

Repository 实现

image.png

📌 在本项目中,异常是在 Repository 层中被处理的。 Repository 最清楚异常的来源,因此在这里将技术异常转换为业务可理解的结果。


Domain 层:核心业务逻辑(What)

Domain 层只关心:

我要做什么,而不是怎么做

Repository 接口(契约)

image.png

UseCase:业务行为的封装

image.png

📌 UseCase 不负责捕获异常 📌 它只组合和执行业务规则 📌 Domain 层因此保持高度纯净


Presentation 层:UI 展示(Show)

Presentation 层负责将数据转换为用户可感知的界面状态。

ViewModel

image.png

特点:

  • ViewModel 不直接依赖 Repository
  • 只通过 UseCase 与 Domain 层交互
  • 专注于 UI State 管理

UI(Compose / XML)只需根据 State 渲染界面。


关于异常处理:为什么放在 Repository 层?

在本项目中,异常处理主要集中在 Repository(Data 层)中完成,而不是在 UseCase 层统一 try-catch。

原因包括:

  • Repository 最了解异常的真实来源(网络、数据库、解析)
  • 可以在这里将技术异常转换为业务错误
  • 避免将 Retrofit、HTTP Code 等细节泄露到 Domain 层
  • 保持 Domain 层的纯净和稳定

这种做法在 Android 工程实践中非常常见,也更利于长期维护。


依赖注入:将各层连接起来

为了将接口和实现解耦,本项目使用 Koin 进行依赖注入:

image.png

通过依赖注入:

  • Domain 层只定义接口
  • Data 层提供实现
  • Presentation 层只消费能力
  • 各层之间无直接耦合

总结

通过 CleanArc 这个示例项目,我们可以看到 Clean Architecture 带来的价值:

  • 关注点分离:UI、业务、数据各司其职
  • 可测试性强:UseCase 和 ViewModel 易于单元测试
  • 高可维护性:修改数据来源不会影响业务层
  • 适合长期演进的项目

Clean Architecture 对于中大型项目来说,它能显著降低维护成本,让代码结构更加清晰、可控。


示例代码

📦 项目完整代码已上传至 GitHub:

👉 CleanArc 示例项目 🔗 github.com/yourname/Cl…

欢迎 Star ⭐。