Android Compose开发中容易混淆的mutableStateOf和MutableStateFlow

237 阅读1分钟

在Android 使用Compose开发过程中,总是会绕不开使用State,而更新State可以用到mutableStateOf和MutableStateFlow。这两种对于初学者来说会分不清,下面就探讨二者的区别。

先说结论mutableStateOf和MutableStateFlow就类似于Java和JavaScript一样,本质没有任何联系;

mutableStateOf:属于Jetpack Compose的运行时状态管理,常用于在Composable函数中触发重组。

@Composable
fun Counter() {
    var count by remember { mutableStateOf(0) }
    Button(onClick = {count++}) {
        Text("$count")
    }
}

上面的代码执行结果是,只要点击按钮,按钮上的数字就会+1。

MutableStateFlow呢?MutableStateFlow是Kotlin协程库中提供的一种特殊类型的Flow,它代表一个状态流。它总是有一个当前值,并且会向收集者发出最新的值和后续的变化。既然是Flow那么他最主要的使用场景就是在ViewModel中使用:

class MyViewModel {
    private val _count = MutableStateFlow(0)
}

在Composable函数中我们是通过State来更新状态的,如何将MutableStateFlow转换为State呢?1、将MutableStateFlow转换为StateFlow,2、然后在composable方法中将StateFlow转换为State;具体参考如下面的①和②(注:下面使用到了Hilt技术,如有不会可查阅相关资料)

@HiltViewModel
class MyViewModel @Inject constructor():ViewModel() {
    private val _counter  = MutableStateFlow(0)
    val counter: StateFlow<Int> = _counter.asStateFlow() //-------① 转换为StateFlow

    fun increment() {
        _counter .update { it + 1 }
    }
}
@Composable
fun Counter() {
    val viewModel = hiltViewModel<MyViewModel>()
    val count by viewModel.counter.collectAsState()  //-------② 调用collectAsState方法
    Button(onClick = {viewModel.increment()}) {
        Text("$count")
    }
}

上面的代码执行结果是,只要点击按钮,按钮上的数字就会+1。

或许你会问mutableStateOf可以写在viewModel中么?当然可以。并且我也建议你那样做。

@HiltViewModel
class MyViewModel @Inject constructor():ViewModel() {
    private val _counter = mutableStateOf(0)
    val counter: State<Int> get() = _counter 

    fun increment() {
        _counter.value++
    }
}
@Composable
fun Counter() {
    val viewModel = hiltViewModel<MyViewModel>()
    val count by viewModel.counter 
    Button(onClick = {viewModel.increment()}) {
        Text("$count")
    }
}

上面的代码执行结果还是,只要点击按钮,按钮上的数字就会+1。

通过上面的操作相比大家已经明显感觉出来了mutableStateOf和MutableStateFlow的明显区别之一就是mutableStateOf 可以直接驱动重组,而MutableStateFlow还需collectAsState()转换一下。

另外最重要的一点MutableStateFlow是Flow,Flow就能处理业务逻辑了(如网络请求结果、密集型计算、查询数据库等),并且Flow可以做一些操作,将原始数据转换为我们期望的数据类型,这方面Flow先天占据优势。

如何选择二者呢?最简单的一句话mutableStateOf只适合纯UI内部状态(如动画进度、文本框内容),否则统一使用MutableStateFlow更可靠。因为MutableStateFlow可以操作线程,支持多线程更新,而mutableStateOf线程不安全,需要主线程更新,这一部分本文不做探究。