首先,先看看不借助任何架构的 Compose 代码是怎样的?
不使用架构的情况下,逻辑代码将与UI代码耦合在一起,在Compose中这种弊端显得尤为明显。常规 Android 开发默认引入了 MVC 思想,XML的布局方式使得UI层与逻辑层有了初步的解耦。但是 Compose 中,布局和逻辑同样都使用Kotlin实现,当布局中夹了杂逻辑,界限变得更加模糊。
此外,Compose UI中混入逻辑代码会带来更多的潜在隐患。由于 Composable 会频繁重组,逻辑代码中如果涉及I/O 就必须当做 SideEffect{} 处理、一些不能随重组频繁创建的对象也必须使用 remember{} 保存,当这些逻辑散落在UI中时,无形中增加了开发者的心智负担,很容易发生遗漏。
Sample 的业务场景特别简单,UI中出现少许 remember{} 、LaunchedEffect{} 似乎也没什么不妥,对于一些相对简单的业务场景出现下面这样的代码没有问题:
@Composable
fun NoArchitectureResultScreen(
answer: String
) {
val isLoading = remember { mutableStateOf(false) }
val dataRepository = remember { DataRepository() }
var result: List by remember { mutableStateOf(emptyList()) }
LaunchedEffect(Unit) {
isLoading.value = true
result = withContext(Dispatchers.IO) { dataRepository.getArticlesList(answer).data.datas }
isLoading.value = false
}
SearchResultScreen(result, isLoading.value , answer)
}
但是,当业务足够复杂时,你会发现这样的代码是难以忍受的。这正如在 React 前端开发中,虽然 Hooks 提供了处理逻辑的能力,但却依然无法取代 Redux。
Android中的常见架构模式
===========================================================================
MVP、MVVM、MVI 是 Android中的而一些常见架构模式,它们的目的都是服务于UI层与逻辑层的解耦,只是在解耦方式上有所不同,如何选择取决于使用者的喜好以及项目的特点
“没有最好的架构,只有最合适的架构。”
那么在 Compose 项目中何种架构最合适呢?
MVP
===============================================================
MVP 主要特点是 Presenter 与 View 之间通过接口通信, Presenter 通过调用 View 的方法实现UI的更新。
这要求 Presenter 需要持有一个 View 层对象的引用,但是 Compose 显然无法获得这种引用,因为用来创建 UI 的 Composable 必须要求返回 Unit,如下:
@Composable
fun HomeScreen() {
Column {
Text(“Hello World!”)
}
}
官方文档中对无返回值的要求也进行了明确约束:
The function doesn’t return anything. Compose functions that emit UI do not need to return anything, because they describe the desired screen state instead of constructing UI widgets. https://developer.android.com/jetpack/compose/mental-model
Compose UI 既然存在于 Android 体系中,必定需要有一个与 Android 世界连接的起点,起点处可能是一个 Activity 或者 Fragment,用他们做UI层的引用句柄不可以吗?
理论上可以,但是当 Activity 接收 Presenter 通知后,仍然无法在内部获取局部引用,只能设法触发整体Recomposition,这完全丧失了 MVP 的优势,即通过获取局部引用进行精准刷新。
通过分析可以得到结论:“MVP 这种依赖接口通信的解耦方式无法在 Compose 项目中使用”