• 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
          }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70

    如上面代码所示,在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组件。

  • 相关阅读:
    Elasticsearch:在 Java 客户端应用中管理索引 - Elastic Stack 8.x
    【三维点云】CC教程1(Context Capture)
    高并发系统谨防被一行日志击垮
    JAVA的由来:要不要干一杯95年的Java
    PHP低代码开发引擎—流程引擎
    Ae 效果:CC Lens
    计算机网络概述
    java反射
    Bergsoft NextSuite (VCL) 不同的方式提供数据
    什么是Java中的反射(Reflection),如何使用它
  • 原文地址:https://blog.csdn.net/zxj2589/article/details/132850403