Android现代开发推荐 | Android Showcase 2.0
Android Showcase是一个完整的Android应用程序示例,它使用了现代的Android应用程序开发方法,集成了流行的开发工具、库和代码检查工具,以及强大的测试框架和持续集成(CI)设置。该项目的主要重点是推广模块化、可扩展、可维护和可测试的架构,并结合了最佳的软件开发实践。即使这个应用程序看起来很简单,它包含了所有关键组件,为强大的大规模应用程序打下了基础。
该项目中采用的设计原则和架构选择非常适合更大的团队和更长的应用程序生命周期。这个应用程序不仅展示了功能,而且证明了良好结构化和编写的代码如何作为可扩展和可维护软件开发项目的稳定支柱。无论是新手还是有经验的开发者,都可以从这个项目中学到很多东西。
应用简介
Android Showcase是一个展示各种音乐专辑信息的简单应用程序,它通过使用Last.fm音乐平台API动态获取数据。该应用程序包含多个特性模块,其中包括以下屏幕:
- 专辑列表屏幕(Album list screen):显示专辑列表
- 专辑详细信息屏幕(Album detail screen):显示所选专辑的信息
- 个人资料屏幕(Profile screen):目前是空白(WiP)
- 收藏夹屏幕(Favourites screen):目前是空白(WiP)
这些屏幕旨在展示应用程序设计和架构的不同方面,以及如何将它们整合到一个完整的Android应用程序中。无论您是初学者还是有经验的开发者,都可以从这个应用程序中学到很多东西。
技术栈
该项目利用 Android 生态系统中的最佳实践和许多流行的库和工具。除非有很好的理由使用非稳定的依赖项,否则大多数库都是稳定版本。
- 技术栈
- 100% Kotlin
- 协程 - 执行后台操作
- Kotlin Flow - 跨越所有应用层的数据流,包括视图。
- Kotlin 符号处理 - 启用编译器插件
- Kotlin 序列化 - 解析 JSON
- Retrofit - 网络通信
- Jetpack
- Compose - 现代、本地 UI 工具包
- Navigation - 应用内导航
- Lifecycle - 在生命周期状态更改时执行操作
- ViewModel - 以生命周期感知的方式存储和管理与 UI 相关的数据
- Room - 存储离线缓存
- Koin - 依赖注入(依赖检索)
- Coil - 图片加载库
- Lottie - 动画库
- 100% Kotlin
- 现代架构
- Clean Architecture
- 使用 Navigation 组件 的单一活动架构
- MVVM + MVI(表示层)
- Android 架构组件
(ViewModel
, Kotlin Flow
, Navigation) - Android KTX - Jetpack Kotlin 扩展
- UI
- 响应式 UI
- Jetpack Compose - 现代、本地 UI 工具包(用于 Fragment)
- View Binding - 检索 XML 视图 ID
(仅用于 NavHostActivity) - Material Design 3 - 应用设计系统,提供 UI 组件
- 主题选择
- 深色主题 - 应用程序的深色主题(Android 10+)
- 动态主题 - 使用生成的基于壁纸的主题(Android 12+)
- CI
- GitHub Actions
- 自动 PR 验证,包括测试、linter 和第三方在线工具
- 测试
- 单元测试(通过 android-junit5 使用 JUnit 5)- 测试单个类
- Konsist - 测试代码约定和架构规则
- UI 测试(Espresso)-
测试用户界面(WiP) - Mockk - 模拟框架
- Kluent - 断言框架
- 静态分析工具(linter)
- Ktlint - 验证代码格式
- Detekt - 验证代码复杂度和代码气味
- Android Lint - 验证 Android 平台使用情况
- Gradle
- Gradle Kotlin DSL - 定义构建脚本
- 自定义任务
- Gradle 插件
- Android Gradle - 标准 Android 插件
- Test Logger - 格式化测试日志
- SafeArgs - 在导航目的地之间传递数据
- Android-junit5 - 使用 JUnit 5 与 Android
- 版本目录 - 定义依赖关系
- 类型安全访问器
- GitHub 引导
- Renovate - 自动更新依赖项
- Stale - 自动关闭陈旧的问题和拉取请求,这些问题和拉取请求在项目中容易积累
- 其他工具
- Charles Proxy - 在
debug
构建中启用网络流量嗅探。
- Charles Proxy - 在
模块化架构
我们使用模块化的方式来减少大型系统的复杂性。每个模块是一个独立的构建块,具有明确的目标。我们将每个特性看作是可重用的组件,类似于microservice或私有库。
采用模块化的代码库方法有以下好处:
- 可重用性 - 可以共享代码并从相同的基础构建多个应用程序。应用程序应该是其特性的总和,其中特性被组织为单独的模块。
- 关注点分离 - 每个模块都有明确的API。与特性相关的类位于不同的模块中,并且没有显式的模块依赖项不能引用它们。我们严格控制着哪些内容对代码库的其他部分公开。
- 特性可以并行开发,例如由不同的团队
- 每个特性可以独立于其他特性进行开发
- 构建时间更快
模块类型和模块依赖关系
下面的图表展示了项目模块(Gradle 子项目)之间的依赖关系。
应用程序有三种类型的模块:
app
模块 - 这是主模块。它包含将多个模块连接在一起的代码(类、依赖注入设置、NavHostActivity
等)和基本应用程序配置(Retrofit 配置、所需权限设置、自定义Application
类等)。feature_x
模块 - 最常见的模块类型,包含与给定特性相关的所有代码。可以在feature
模块之间共享一些资源或代码(当前应用程序没有此类模块)。feature_base
模块 - 特性模块依赖于它们以共享公共代码。
特性模块结构
我们采用 Clean Architecture
在模块级别实现 - 每个模块都包含自己一组 Clean Architecture 层:
注意,
app
模块和library_x
模块的结构与特性模块的结构稍有不同。
每个特性模块包含非层组件和3个具有不同责任集的层。
表示层
该层最接近用户在屏幕上看到的内容。
presentation
层结合了 MVVM
和 MVI
模式:
MVVM
- 使用 Jetpack 的ViewModel
封装一个common UI state
。它通过可观察的状态持有者(Kotlin Flow
)公开状态。MVI
-action
修改common UI state
并通过Kotlin Flow
向视图发出新的状态。
common state
是每个视图的单一真理来源。这种解决方案源于 单向数据流 和 Redux 原则。
这种方法有助于创建一致的状态。状态通过 collectAsUiStateWithLifecycle
方法收集。Flow 集合以受生命周期管理的方式进行,因此不会浪费资源。
状态使用 Immutable 注解标记,Jetpack Compose 使用该注解启用组合优化。
组件:
- 视图(Fragment) - 观察通用视图状态(通过
Kotlin Flow
)。Compose 将由 Kotlin Flow 发出的状态转换为应用程序 UI。将用户交互传递给ViewModel
。视图很难进行测试,因此应尽可能简单。 - ViewModel - 向视图发出(通过
Kotlin Flow
)视图状态的更改,并处理用户交互(这些视图模型不仅仅是POJO 类)。 - ViewState - 单个视图的通用状态
- StateTimeTravelDebugger - 记录操作和视图状态转换以便进行调试。
- NavManager - 单例,用于在
NavHostActivity
内处理所有导航事件(而不是在每个视图内单独处理)。
领域层
这是应用程序的核心层。请注意,domain
层独立于其他任何层。这样可以使领域模型和业务逻辑独立于其他层。换句话说,对其他层的更改(例如更改数据库(data
层)或屏幕 UI(presentation
层))理想情况下不会影响 domain
层的任何代码更改。
组件:
- UseCase - 包含业务逻辑
- DomainModel - 定义应用程序中将使用的数据的核心结构。这是应用程序数据的真理来源。
- Repository 接口 - 保持
domain
层独立于data layer
(依赖反转)。
数据层
包装应用程序数据。为 domain
层提供数据,例如从互联网检索数据并在设备离线时将数据缓存到磁盘缓存中。
组件:
- Repository 将数据公开给
domain
层。根据应用程序结构和外部 API 的质量,存储库还可以合并、过滤和转换数据。这些操作旨在为domain
层创建高质量的数据源。存储库(一个或多个)负责从Data Source
中读取并构建领域模型,并接受要写入Data Source
的领域模型。 - Mapper - 将
data model
映射到domain model
(使domain
层独立于data
层)。
该应用程序有两个 Data Sources
- Retrofit
(用于网络访问)和 Room
(用于访问设备持久存储的本地存储)。这些数据源可以被视为一个隐式子层。每个数据源由多个类组成:
- Retrofit Service - 定义一组 API 端点
- Retrofit Response Model - 定义给定端点的网络对象(数据的顶层模型包含
ApiModels
) - Retrofit Api Data Model - 定义网络对象(响应模型的子对象)
- Room Database - 持久性数据库,用于存储应用程序数据
- Room DAO - 与存储的数据进行交互
- Room Entity - 存储对象的定义
Retrofit API Data Models
和 Room Entities
都包含注解,因此给定的框架了解如何解析数据为对象。
数据流
下图展示了当用户与“专辑列表界面”交互时的应用程序数据流:
依赖管理
使用 Gradle 版本目录 作为集中化的依赖管理,共享第三方依赖项坐标(分组、构件、版本)跨所有模块(Gradle 项目和子项目)。
所有依赖项都存储在 settings.gradle.kts 文件中(默认位置)。Gradle 版本目录包括几个主要部分:
[versions]
- 声明可被所有依赖项引用的版本[libraries]
- 声明库坐标的别名[bundles]
- 声明依赖捆绑包(组)[plugins]
- 声明 Gradle 插件依赖项
每个特性模块都依赖于 feature_base
模块,因此依赖项在不需要在每个特性模块中显式添加的情况下共享。
该项目启用了 TYPESAFE_PROJECT_ACCESSORS
实验性 Gradle 功能,以生成类型安全的访问器,以引用其他项目。
// Before
implementation(project(":feature_album"))
// After
implementation(projects.featureAlbum)
灵感
以下是一些额外的资源。
快速参考表
- Material Theme Builder - 生成动态材料主题并查看其实际效果
- Compose Material 3 Components
- 包含材料组件的列表 - Core App Quality Checklist - 学习如何构建高质量应用程序
- Android Ecosystem Cheat Sheet - 包含 200+ 最重要的工具的板
- Kotlin Coroutines - Use Cases on Android -
最流行的协程用途
Android 项目
其他高质量的项目将帮助您找到适用于您的项目的解决方案(随机顺序):
- Compose Samples - 存储库包含一组个别的 Android Studio
- Jetpack Compose Playground - 这是一个 Jetpack Compose 示例
项目 - Now Android - 完全使用 Kotlin 和 Jetpack Compose 构建的功能齐全的 Android 应用程序
- WhatsApp Clone Compose - 使用 Jetpack Compose 和 Stream Chat SDK
构建的 WhatsApp 克隆应用程序,用于帮助您了解 Android 中的 Compose - Iosched - Google IO 2019 和 2021 的官方 Android 应用程序
- Android Architecture Blueprints v2 - 展示了各种 Android
架构方法来开发 Android 应用程序 - Github Browser Sample - 多个小项目,演示了 Android
架构组件的使用 - Clean Architecture Boilerplate - 用于 Android 的清晰
架构 - Roxie -
common state
方法的坚实示例以及非常好的文档 - Kotlin Android Template - 模板,可让您在几秒钟内创建预配置的 Android Kotlin 项目
项目地址
https://github.com/igorwojda/android-showcase