Jetpack Compose 在 ViewModel 中观察 mutableStateOf

Jetpack Compose Observe mutableStateOf in ViewModel

我需要更新用户配置文件开关

  1. 视图模型
class ProfileViewModel : BaseViewModel() {

    var greet = mutableStateOf(user.pushSetting.greet)
    var message = mutableStateOf(user.pushSetting.message)
    var messageDetails = mutableStateOf(user.pushSetting.messageDetails)

    var follow = mutableStateOf(user.pushSetting)
    var like = mutableStateOf(user.pushSetting.like)
    var comment = mutableStateOf(user.pushSetting.comment)

    fun updateUser() {
        println("--")
    }
}

2.Composable

@Composable
fun SettingCard(viewModel: ProfileViewModel) {

    Lists {
        Section {
            TextRow(text = "手机号码") { }
            TextRow(text = "修改密码", line = false) { }
        }

        Section {
            SwitchRow(text = "新好友通知", checkedState = viewModel.greet)
            SwitchRow(text = "新消息通知", checkedState = viewModel.message)
            SwitchRow(text = "消息显示详细", line = false, checkedState = viewModel.messageDetails)
        }
    }
}

3.SwitchRow

@Composable
fun SwitchRow(text: String, line: Boolean = true, checkedState: MutableState<Boolean>) {

    ListItem(
        text = { Text(text) },
        trailing = {
            Switch(
                checked = checkedState.value,
                onCheckedChange = { checkedState.value = it },
                colors = SwitchDefaults.colors(checkedThumbColor = MaterialTheme.colors.primary)
            )
        }
    )
}

如何观察开关的变化并在ViewModel中调用updateUser()

我知道这是一种方式,但并不理想。每次初始化都会调用网络更新。有更好的解决方案吗?

LaunchedEffect(viewModel.greet) {
     viewModel.updateUser()
}

SwitchRow 中添加回调 lamba 并在任何状态更改时调用它

@Composable
fun SettingCard(viewModel: ProfileViewModel) {
Lists {
    Section {
        TextRow(text = "手机号码") { }
        TextRow(text = "修改密码", line = false) { }
    }

    Section {
        SwitchRow(text = "新好友通知", checkedState = viewModel.greet) {
            viewModel.updateUser()
        }
        SwitchRow(text = "新消息通知", checkedState = viewModel.message) {
            viewModel.updateUser()
        }
        SwitchRow(text = "消息显示详细", line = false, checkedState = viewModel.messageDetails) {
            viewModel.updateUser()
        }
    }
}
}

@Composable
   fun SwitchRow(
   text: String,
   line: Boolean = true,
   checkedState: MutableState<Boolean>,
   onChange: (Boolean) -> Unit
) {
ListItem(
    text = { Text(text) },
    trailing = {
        Switch(
            checked = checkedState.value,
            onCheckedChange = {
                onChange(it)
                checkedState.value = it
            },
            colors = SwitchDefaults.colors(checkedThumbColor = MaterialTheme.colors.primary)
        )
    }
)
}

另一种方法:

您可以将 MutableStateFlow<T> 保留在您的视图模型中并开始在 init 方法中观察它并从 SwitchRow 向它发送一个值,例如 viewModel.stateFlow.value = 值。 请记住,MutableStateFlow 只会在值更改时触发。如果您两次设置相同的值,它将丢弃第二个值并执行第一个值。

val stateFlow = MutableStateFlow<Boolean?>(null)

init {
    stateFlow
        .filterNotNull()
        .onEach { updateUser() }
        .launchIn(viewModelScope)
}

在switchRow

viewmodel.stateFlow.value = !(viewmodel.stateFlow.value?: false)

这可能是一种可能的解决方案。你可以用你方便的方式实现它。

最好的解决方案是 unidirectional flowSwitchRow 以及 @Codecameo 建议的 lambda。

但是如果你想在你的 Viewmodel 中观察一个 MutableState 你可以使用 snapshotFlows as

var greet: MutableState<Boolean> = mutableStateOf(user.pushSetting.greet)

init {
    snapshotFlow { greet.value }
        .onEach {
            updateUser()
        }
        .launchIn(viewModelScope)
        //...
}

Create a Flow from observable Snapshot state. (e.g. state holders returned by mutableStateOf.) snapshotFlow creates a Flow that runs block when collected and emits the result, recording any snapshot state that was accessed. While collection continues, if a new Snapshot is applied that changes state accessed by block, the flow will run block again, re-recording the snapshot state that was accessed. If the result of block is not equal to the previous result, the flow will emit that new result. (This behavior is similar to that of Flow.distinctUntilChanged.) Collection will continue indefinitely unless it is explicitly cancelled or limited by the use of other Flow operators.