Android Jetpack Compose 使用 ViewModel
1.ViewModel为啥不可或缺
我们已经了解到了rememberSavable可以在屏幕旋转,当前Activity被系统回收时保存状态。ViewModel正好也是干这个活的,那为啥没有使用rememberSavable替换ViewModel呢?比如我们在前面的文章中用到的计数器例子,可以使用remremberSavable来保存状态,也可以用viewModel来保存状态,但是这只是一个Demo而已,在真实的项目中,业务逻辑是不会只是简单的加加减减,往往会复杂得多得多,如果将代码全放到Stateful Composable中,会导致UI的职责不清晰,毕竟我们的Composable的主要职责是显示UI。
所以,在复杂的业务逻辑下,我们可以将Stateful的状态提到ViewModel中管理,这样Stateful Composable也就变成了一个Stateless Composable,通过参数传入不同的ViewModel即可替换具体的业务逻辑,大大增加了可复用性和可测试性
2 在Compose UI中使用ViewModel
借用前面的计数器例子,这里使用Compose UI 和ViewModel的配合,实现一个计数器例子,代码如下:
class ComposeCounterAct : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MyComposeTheme {
// A surface container using the 'background' color from the theme
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
TestCounter()
}
}
}
}
@Composable
fun TestCounter(){
val viewModel:ComposeCounterViewModel = viewModel()
CounterComponent(viewModel.counter.value,viewModel::increment,viewModel::decrement)
}
@Composable
fun CounterComponent(
counter: Int, // 重组时传入当前需要显示的计数
onIncrement: () -> Unit,// 回调点击加号的事件
onDecrement: () -> Unit // 回调单击减号的事件
) {
Column(modifier = Modifier.padding(16.dp)) {
Text(
"$counter",
Modifier.fillMaxWidth(),
textAlign = TextAlign.Center
)
Row {
Button(
onClick = { onDecrement() },
modifier = Modifier.weight(1f)
) {
Text("-")
}
Spacer(Modifier.width(16.dp))
Button(
onClick = { onIncrement() },
modifier = Modifier.weight(1f)
) {
Text("+")
}
}
}
}
}
class ComposeCounterViewModel:ViewModel(){
private val _counter = mutableStateOf(0)
val counter: State<Int> = _counter
fun increment(){
_counter.value = _counter.value + 1
}
fun decrement(){
if(_counter.value>0){
_counter.value = _counter.value -1
}
}
}
如上面代码所示,在
Compose UI
对于ViewModel
的使用和传统的view基本相同,在Compose中viewModel()
方法是一个Composable
方法,它的作用是在Composable
中创建ViewModel,TestCounter
通过viewModel()方法创建了一个ComposeCounterViewModel
类型的ViewModel,这个ViewModel持有计数器的状态。
注意:在Composable中使用viewModel()方法需要添加依赖: implementation('androidx.lifecycle:lifecycle-viewmodel-compose:2.6.2') ,否则会提示方法找不到。
这里的viewModel()方法会从当前最近的ViewModelStore中获取ViewModel实例,这个ViewModelStore可能是一个Activity,也可能是一个Fragment,如果ViewModel实例不存在,就创建一个新的并且存入ViewModelStore。只要是ViewModelStore不销毁,其内部的ViewModel实例就会一直存活。例如一个Activity中的Composable通过viewModel()方法创建的ViewModel被当前的Activity所持有。在Activity销毁之前,ViewModel会一直存在,viewModel()的每次调用都会返回一个实例,所以我们不用remember缓存也可以。
注意: 调用viewModel()方法的Composable无法进行预览,若需要进行预览,可以从持有ViewModel的Composable中将需要预览的部分提取成StateLess组件,如文中的CounterComponent组件。
更多推荐
所有评论(0)