前一篇文章大概了解了一下 MvRx 框架 认识 Mavericks,那么在 Compose 里是否仍然适用呢,现在一起学习构建一个简单的应用来感受下,可以明显感觉到 MvRx 与 Compose 可以配合的很好,甚至比传统视图更合适。使用 Compose 构建 UI,MvRx 可用于业务逻辑、数据获取、对象依赖注入等。
最新的 Mavericks 已经完全 Compose。
implementation 'com.airbnb.android:mavericks-compose:2.6.1'
创建 MavericksViewModel
先创建一个简单的 CounterViewModel,它的状态包含一个 count 属性,ViewModel 有一个 incrementCount() 方法。
data class CounterState(
val count: Int = 0
) : MavericksState
class CounterViewModel(initialState: CounterState) :
MavericksViewModel<CounterState>(initialState) {
fun incrementCount() = setState { copy(count = count + 1) }
}
访问 ViewModel
只需要在 Composable 函数里调用 mavericksViewModel() 来获取 ViewModel 实例。
@Composable
fun IncrementCountComponent() {
val viewModel: CounterViewModel = mavericksViewModel()
Button(onClick = { viewModel.incrementCount() }) {
Text("Increment Count")
}
}
默认情况下,将作用于最近的 LocalLifeyclerOwner,可能是 NavBackStateEntry、Fragment 或者 Activity,意味着该 LocalLifeyclerOwner 下的所有 Composable 将获取到相同的 ViewModel 实例。如果需要,也可以指定范围,比如 mavericksActivityViewModel() 等。
@Composable
fun IncrementCountComponent() {
val viewModel: CounterViewModel = mavericksViewModel(LocalContext.current as LifecycleOwner)
val viewModel1: CounterViewModel = mavericksActivityViewModel()
}
访问 ViewModel 状态
要订阅 ViewModel 里的状态变化,MvRx 提供了 ViewModel.collectAsState()。
@Composable
fun IncrementCountComponent() {
val viewModel: CounterViewModel = mavericksViewModel()
val state by viewModel.collectAsState()
val count1 = viewModel.collectAsState(CounterState::count)
val count2 = viewModel.collectAsState { it.count }
Text("Count is ${state.count}")
Text("Count is $count1")
Text("Count is $count2")
}
要优化使用 collectAsState(),不同 Composable 访问不同的状态属性,在重组时候可以最大限度地减少状态更改时需要完成的工作。因此在 Composable 里订阅几个状态属性比订阅整个状态更理想。
还可以根据状态提升来优化
将 IncrementCountComponent 拆分成有状态和无状态版本,会使 @Preview 等更容易使用。
@Composable
fun IncrementCountComponent() {
val viewModel: CounterViewModel = mavericksViewModel()
val count by viewModel.collectAsState { it.count }
IncrementCountComponent(count)
}
@Composable
fun IncrementCountComponent(count: Int) {
Text("Count is $count")
}
随着 Jetpack Compose 不断成熟,Mavericks 可以成为 Compose 的绝佳补充。