Jetpack Compose 中的架构思想

本文详细介绍了Jetpack Compose的架构思想,包括UI层与数据层的分离,强调单向数据流原则。重点讨论了StateHolder的概念,以及如何通过Stateful和Stateless组件来管理状态。此外,文章还涵盖了State Hoisting、ViewModel的使用,以及如何在Compose中实现状态持久化与恢复。同时,文章提到了Domain Layer和Data Layer在数据处理中的角色,包括UseCase、Repository和Data Model的设计与最佳实践。
摘要由CSDN通过智能技术生成

Jetpack Compose 中的架构总览

在这里插入图片描述

如果应用打算使用 Jetpack Compose 来开发,那么就可以跟以前的MVC、MVP、MVVM等乱七八糟的架构全部说拜拜,这些名词也将在Android开发当中永远地成为历史。因为 Jetpack Compose 的架构思想非常简单,只有UI层数据层两层,即上图所示(其中 Domain Layer 是可选的层)。它的核心思想是单向数据流,以数据模型驱动界面,遵循关注点分离的原则。

上面的架构图同时也为我们重新定义了到底什么是 UI:

在这里插入图片描述

State和逻辑的分类

  • UI element state: UI 元素提升的状态(如ScaffoldState)
  • Screen or UI state: 需要在屏幕上显示的东西(如CartUiState)
  • UI 行为逻辑: 如何显示状态变化(如导航逻辑或显示snackbar)
  • 业务逻辑: 如何处理状态变化(如发起支付或存储用户preferences)

StateHolder

在前面的架构图中可以看到,UI 层其实细分又包含了两层:UI 元素状态容器(StateHolder)。其中 UI 元素 就是我们常见的各种 Composable 组件,而 状态容器 则是承载这些 UI 元素 所需要的各种状态。同时状态容器也会接受从 UI 元素 中产生的各种事件,因为只要有UI交互就一定会产生事件。StateHolder 的存在避免了界面同时成为界面和状态的管理者。有一句话我觉得可以很好的表达它的职责:“吸收事件,生成状态”。

在这里插入图片描述

可以作为 StateHolder 状态容器的一般有两种,一种是使用持有 UI 状态的普通的类来管理,另一种是使用 ViewModel 来管理。

下面是一个使用普通的类来管理 UI 状态的示例:

class MyAppState(
    val scaffoldState: ScaffoldState,
    val navController: NavController,
    private val resources: Resources,
    ...
) {
   
   val bottomBarTabs = /* State */
   val shouldShowBottomBar: Boolean // 决定什么什么时候显示BottomBar的逻辑代码
        get() = /* ... */
   fun navigateToBottomBarRoute(route: String) {
   /* ... */} // 导航逻辑,是UI逻辑的一种类型
   fun showSnackBar(message: String) {
   /* ... */} // 显示SnackBar的逻辑
}

@Composable
fun rememberMyAppState(
    scaffoldState: ScaffoldState = rememberScaffoldState(),
    navController: NavController = rememberNavController(),
    resources: Resources = LocalContext.current.resources,
    ...
) = remember(scaffoldState, navController, resources, ...) {
   
    MyAppState(scaffoldState, navController, resources, /* ... */)
}

然后在 Composable 中使用自定义的 StateHolder 来读取各种状态和执行UI跳转逻辑等。

@Composable
fun MyApp() {
   
    MyApplicationTheme {
   
        val myAppState = rememberMyAppState()
        Scaffold(
            scaffoldState = myAppState.scaffoldState,
            bottomBar = {
   
                if (myAppState.shouldShowBottomBar) {
   
                    BottomBar(
                        tabs = myAppState.bottomBarTabs,
                        navigateToRoute = {
   
                            myAppState.navigateToBottomBarRoute(it)
                        }
                    )
                }
            }
        ) {
   
            NavHost(navController = myAppState.navController,  "WelcomeScreen") {
   /* ... */}
        }
    }
}

注意:凡是要在 Composable 中使用的状态一定要使用 remember ,因为 Composable 是会被重复执行的(重组),所以对于自定义的状态容器类对象也要使用 remember 来创建,最好是提供一个配套的 remember 函数。

官方推荐的可以作为 StateHolder 的正牌状态容器其实是 ViewModel, 因为普通的状态管理类无法做到像 ViewModel 那样在横竖屏切换等配置发生改变的场景时自动恢复(但依然可通过rememberSavable来实现同样效果)。

在这里插入图片描述

从某种意义上讲, ViewModel 只是一种特殊的 StateHolder ,但因为它保存在 ViewModelStore 中,所以有以下特点:

  • 存活范围大:可以脱离 Composition 存在,被所有的 Composable 共享访问。
  • 存活时间长:不会因为横竖屏切换后进程被杀死等情况丢失状态。

因此 ViewModel 适合管理应用级别或者屏幕级别的全局状态,各个 Composable 可以通过 viewModel() 获取 ViewModel 单例达到 “全局共享” 的效果,而且 ViewModel 更倾向于管理那些非 UI 的业务状态,业务状态中的数据往往需要脱离 UI 长期保存。

例如:

data class ExampleUiState(
    val dataToDisplayOnScreen: List<Example> = emptyList(),
    val userMessages: List<Message> = emptyList(),
    val loading: Boolean = false
)

class ExampleViewModel(
    private val repository: UserPreferRepository,
    private val savedStateHandle: SavedStateHandle
): ViewModel() {
   
    var uiState by mutableStateOf(ExampleUiState())
        private set // 私有化set操作,只有当前ViewModel内部可以修改,对外部来说不可修改
    fun someBusinessLogic() {
   
        // 执行业务逻辑
        // savedStateHandle.set("key", uiState)
    }
}

@Composable
fun ExampleScreen(viewModel: ExampleViewModel = viewModel()) {
   
    val uiState = viewModel.uiState
    // ... 使用 uiState 
    Button(onClick = {
    viewModel.someBusinessLogic() }) {
   
        Text("Do Something")
    }
}

在上面代码中,ExampleUiState 中包含了 userMessages 这样的领域层数据,以及 loading 这样的代表数据加载状态的数据,这些都与 UI 无关,适合用 ViewModel 进行管理。此外, ViewModel

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

川峰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值