Mavericks Meet Jetpack Compose

1,279 阅读1分钟

前一篇文章大概了解了一下 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,可能是 NavBackStateEntryFragment 或者 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 里订阅几个状态属性比订阅整个状态更理想。

还可以根据状态提升来优化

udf-hello-screen.png

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 的绝佳补充。