Android 架构建议

本文介绍了现代Android开发中的关键架构原则,如关注点分离、MVI模式(Model-UIState)、单向数据流以及分层架构(UILayer、DomainLayer和DataLayer)。还探讨了如何使用KotlinCoroutines和LiveData,强调了数据驱动UI和持久化数据的重要性。
摘要由CSDN通过智能技术生成

一、概述

1.1 通用架构原则

1.1.1 关注点分离

在Activity或Fragment中编写所有代码是一个常见的错误。这些基于UI的类应该只包含处理UI和操作系统交互的逻辑。通过使这些类尽可能精简,我们可以避免与组件生命周期相关的许多问题,并提高这些类的可测试性。

1.1.2 数据模型驱动UI

1.1.3 单一可信任数据源

当一个新的数据类型在你的应用中被定义时,你应该给它分配一个单一的可信任数据源(SSOT)。SSOT是该数据的所有者,并且只有SSOT可以修改或改变它。为了实现这一点,SSOT使用不可变类型公开数据,为了修改数据,SSOT公开其他类型可以调用的函数或接收事件。

1.1.4 单向数据流

在UDF中,状态只在一个方向上流动。在相反方向上修改数据流的事件。

1.2 MVI

Model - UI State.
View - Activity / Fragment / Composable
Intent - 用户或应用程序本身执行操作的意图或愿望。

1.3 Clean

干净的架构代表一组实践,由这些实践产生的系统有以下特点:
  • 独立于框架
  • 可测试的
  • 独立于UI
  • 独立于数据源
  • 独立于任何外部依赖

二、推荐应用架构

2.1 UI Layer

UI是将UI元素与UI状态绑定在屏幕上的结果。

  • 状态向下流动而事件向上流动的模式称为单向数据流(UDF)。
  • ViewModel保存并公开供UI使用的状态。UI状态是由ViewModel转换的应用程序数据。
  • UI通知ViewModel用户事件。
  • ViewModel处理用户操作并更新状态。 -更新后的状态反馈到UI进行渲染。
  • 对于任何导致状态突变的事件都要重复上述操作。

class NewsViewModel(
    private val repository: NewsRepository,
    ...
) : ViewModel() {

    private val _uiState = MutableStateFlow(NewsUiState())
    val uiState: StateFlow<NewsUiState> = _uiState.asStateFlow()

    private var fetchJob: Job? = null

    fun fetchArticles(category: String) {
        fetchJob?.cancel()
        fetchJob = viewModelScope.launch {
            try {
                val newsItems = repository.newsItemsForCategory(category)
                _uiState.update {
                    it.copy(newsItems = newsItems)
                }
            } catch (ioe: IOException) {
                // Handle the error and notify the UI when appropriate.
                _uiState.update {
                    val messages = getMessagesFromThrowable(ioe)
                    it.copy(userMessages = messages)
                 }
            }
        }
    }
}

2.2 Domain Layer

Domain层是位于UI层和数据层之间的可选层

class MyUseCase(
    private val defaultDispatcher: CoroutineDispatcher = Dispatchers.Default
) {

    suspend operator fun invoke(...) = withContext(defaultDispatcher) {
        // Long-running blocking operations happen on a background thread.
    }
}

2.3 Data Layer

Data层包含应用程序数据和业务逻辑。业务逻辑是为应用程序提供价值的东西——它由现实世界的业务规则组成,这些规则决定了应用程序数据必须如何创建、存储和更改。

重要的是,每个存储库定义一个单一的事实来源。事实的来源总是包含一致的、正确的和最新的数据。事实上,从存储库公开的数据应该始终是直接来自事实来源的数据。
事实的来源可以是数据源(例如数据库),甚至可以是存储库可能包含的内存缓存。存储库组合不同的数据源并解决数据源之间的任何潜在冲突,以便定期或由于用户输入事件而更新单个事实源。
应用程序中的不同存储库可能有不同的事实来源。例如,LoginRepository类可以使用它的缓存作为事实的来源,PaymentsRepository类可以使用网络数据源。
为了提供离线优先支持,建议使用本地数据源(例如数据库)作为事实来源。

class ExampleRepository(
    private val exampleRemoteDataSource: ExampleRemoteDataSource, // network
    private val exampleLocalDataSource: ExampleLocalDataSource // database
) {

    val data: Flow<Example> = ...

    suspend fun modifyData(example: Example) { ... }
}

三、结论

3.1 架构原则及目标

关注点分离

  • UI / Domain / Data三层式架构
  • 单向数据流
  • 职责及边界清晰的模块划分

数据驱动UI

  • 数据独立于UI,不跟随页面的生命周期,方便复用及测试
  • 数据可持久化,进程结束时数据可保留;页面重建时UI状态及内存数据可恢复

可持续演进

  • 可维护性,有长期技术支持
  • 伸缩性,可进化升级

3.2 实现细节

UI Layer

  • UI elements - Activity + Fragment + Views (optional: Jetpack Compose)
  • State holders - ViewModel
  • UDF - StateFlow (backup: LiveData)

Domain Layer

  • Threading - Prefer suspend function (Kotlin Coroutines)

Data Layer

  • Repository - Using flow-friendly APIs or 3rd library (Room \ Retrofit \ etc.)

四、参考资料

4.1 架构相关

4.1.1 Architecture - Modern Android Development Skills

https://www.youtube.com/watch?v=TPWmfJq16rA&list=PLWz5rJ2EKKc8GZWCbUm3tBXKeqIi3rcVX

4.1.2 Google架构指南

https://developer.android.com/jetpack/guide

4.1.3 Architecting Android… Reloaded

https://github.com/android10/Android-CleanArchitecture-Kotlin

https://fernandocejas.com/2018/05/07/architecting-android-reloaded/#data-layer-repository-pattern-to-the-rescue

4.2 完整项目参考

4.2.1 Tivi

https://github.com/chrisbanes/tivi

4.2.2 sunflower

https://github.com/android/sunflower

4.2.3 Android Architecture Blueprints

https://github.com/android/architecture-samples

4.2.4 Now in Android App

https://github.com/android/nowinandroid

4.3 Coroutines相关

4.3.1 深入浅出协程、线程和并发问题

https://mp.weixin.qq.com/s?__biz=Mzk0NDIwMTExNw==&mid=2247491523&idx=1&sn=e1ad8c96a90254e9e68667b1ec2f8786

4.3.2 Kotlin Vocabulary | 揭秘协程中的 suspend 修饰符

https://mp.weixin.qq.com/s?__biz=MzAwODY4OTk2Mg==&mid=2652055127&idx=2&sn=283de8250bfc8a7bd8287a7aadad1339

4.3.3 从 LiveData 迁移到 Kotlin 数据流

https://mp.weixin.qq.com/s?__biz=Mzk0NDIwMTExNw==&mid=2247493227&idx=1&sn=559909a5cbea791f6a0320ed42655215

https://medium.com/androiddevelopers/migrating-from-livedata-to-kotlins-flow-379292f419fb

4.3.4 使用更为安全的方式收集 Android UI 数据流

https://mp.weixin.qq.com/s?__biz=Mzk0NDIwMTExNw==&mid=2247494116&idx=1&sn=6bd12ff9d62eb2a71fa74060afcac996

https://medium.com/androiddevelopers/a-safer-way-to-collect-flows-from-android-uis-23080b1f8bda

4.3.5 使用 Kotlin Flow 构建数据流 "管道"

https://mp.weixin.qq.com/s?__biz=Mzk0NDIwMTExNw==&mid=2247512636&idx=1&sn=6136e9e4595e957fb97d54c960f8a74f

4.3.6 设计 repeatOnLifecycle API 背后的故事

https://mp.weixin.qq.com/s?__biz=Mzk0NDIwMTExNw==&mid=2247497396&idx=1&sn=d4f447332856ab25a4ab85cf207c1a67

https://medium.com/androiddevelopers/repeatonlifecycle-api-design-story-8670d1a7d333

  • 30
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值