与传统View开发不同的是在ViewModel里面增加了mutableStateOf,那么我们该如何使用mutableStateOf和MutableStateFlow呢?
结论就是,在逻辑简单的情况下,我们使用mutableStateOf来简化逻辑,如果有复杂数据流我们最好使用StateFlow
mutableStateOf的使用
//简单返回数据
var roomResult by mutableStateOf<List<String>?>(null)
//判断加载状态
var isLoading by mutableStateOf(false)
```
```
在compose里面直接使用
val rooms = viewModel.roomResult
但是这里的写法有问题,我们最好不用使用by关键字来初始化变量,这会让这个变量看起来是一个****普通变量 ,并且忽略了它的副作用(这里的副作用就是我们因为这个变量需要额外处理的逻辑)
class RoomViewModel : ViewModel() {
//私有变量:只有 ViewModel 内部可以修改 (Mutable)
private val _roomResult = mutableStateOf<List<String>?>(null)
//公有变量:暴露给 Compose 读取 (Read-only State)
val roomResult: State<List<String>?> = _roomResult
//加载状态同理
private val _isLoading = mutableStateOf(false)
val isLoading: State<Boolean> = _isLoading
//处理状态的方法
fun fetchData() {
//修改时必须显式使用 .value
//这就是所谓的“不忽略副作用”:每次看到 .value,
_isLoading.value = true
//模拟异步操作后的副作用处理
try {
// ... 假设这里是网络请求
_roomResult.value = listOf("Room 101", "Room 102")
} finally {
//副作用:无论成功失败,最后都要关闭加载状态
_isLoading.value = false
}
}
}
在compose函数里面这样使用
val rooms = viewModel.roomResult.value
MutableStateFlow的使用
//私有MutableStateFlow,用于内部修改(通过调用函数)
private val _selectedWeek = MutableStateFlow<Int?>(SchoolCalendar.getWeekOfTerm())
private val _selectedWeekDayNum = MutableStateFlow<Int?>(getInitialDayOfWeek())
private val _selectedBuildNum = MutableStateFlow<Int?>(null)
private val _selectedSections = MutableStateFlow<List<Int>>(emptyList())//节次是多选
//周次
val selectedWeekSet = _selectedWeek.map { setOfNotNull(it) }
//星期
val selectedWeekDaySet = _selectedWeekDayNum.map { setOfNotNull(it) }
//教学楼
val selectedBuildNumSet = _selectedBuildNum.map { setOfNotNull(it) }
//节次(多选)
val selectedSectionsSet = _selectedSections.map { it.toSet() }
//外部改值
fun onWeekChange(week: Int) {
_selectedWeek.value = week
}
fun onWeekDayChange(day: Int) {
_selectedWeekDayNum.value = day
}
fun onBuildChange(build: Int) {
_selectedBuildNum.value = build
}
fun toggleSection(section: Int) {
val current = _selectedSections.value
_selectedSections.value = if (current.contains(section)) {
if (current.size > 1) current - section else current
} else {
current + section
}
}
compose里面的使用
val selectedWeekSet by viewModel.selectedWeekSet.collectAsStateWithLifecycle(
initialValue = emptySet()
)
val selectedWeekDaySet by viewModel.selectedWeekDaySet.collectAsStateWithLifecycle(
initialValue = emptySet()
)
val selectedBuildNumSet by viewModel.selectedBuildNumSet.collectAsStateWithLifecycle(
initialValue = emptySet()
)
val selectedSectionsSet by viewModel.selectedSectionsSet.collectAsStateWithLifecycle(
initialValue = emptySet()
)
可以看到在compose里面还需要手动collectAsStateWithLifecycle转换