从 viewmodel 编写 mutableState

Dec*_*ine 2 android android-jetpack-compose

我有 2 个可变状态ViewModel,希望它们观察我的可组合项中的文本字段。

ViewModel:

@HiltViewModel
class AddEditTransactionViewModel @Inject constructor(
    private val moneyManagerUseCases: MoneyManagerUseCases
) : ViewModel() {

    private val _transactionDescription = mutableStateOf("")
    val transactionDescription: State<String> = _transactionDescription

    private val _transactionAmount = mutableStateOf("")
    val transactionAmount: State<String> = _transactionAmount
Run Code Online (Sandbox Code Playgroud)

Composable:

@Composable
fun AddEditTransactionScreen(
    navController: NavController,
    viewModel: AddEditTransactionViewModel = hiltViewModel(),

    ) {

    // This works
    var descriptionState by remember { mutableStateOf("") }
    var amountState by remember { mutableStateOf("") }

    // This doesn't work
    var viewModelDescriptionState = viewModel.transactionDescription.value
    var viewModelAmountState = viewModel.transactionAmount.value

    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(8.dp),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        TextField(
            value = viewModelDescriptionState,
            onValueChange = { viewModelDescriptionState = it },
            label = { Text(text = "Description") })
        Spacer(modifier = Modifier.padding(20.dp))
        TextField(
            value = viewModelAmountState,
            onValueChange = { viewModelAmountState = it },
            label = { Text(text = "Amount") },
            keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number)
        )
Run Code Online (Sandbox Code Playgroud)

如果我使用可组合项中的状态,它会起作用,但这违背了 ViewModel 的目的。

Phi*_*hov 5

第一行:

var descriptionState by remember { mutableStateOf(") }
Run Code Online (Sandbox Code Playgroud)

它之所以有效,是因为您正在更新通过委托的值mutableState。如果你看看在没有委托的情况下如何做同样的事情,那就更容易理解了:

val descriptionState = remember { mutableStateOf("") }
//...
descriptionState.value = "new value"
Run Code Online (Sandbox Code Playgroud)

remember将在重组之间保存相同的对象,但该对象具有value正在更改的字段。

另一方面,这里:

var viewModelDescriptionState = viewModel.transactionDescription.value
Run Code Online (Sandbox Code Playgroud)

您创建了一个局部变量,并且在重组之间不会保存任何更改。

这通常可以通过在视图模型中创建 setter 函数来解决。您还可以在视图模型中使用委托,如果您想限制它在没有setter的情况下进行更新,您可以添加private set, 而不是使用private _variablepublic variable

var transactionDescription by mutableStateOf("")
    private set

fun updateTransactionDescription(newValue: String) {
    transactionDescription = newValue
}
Run Code Online (Sandbox Code Playgroud)

这被认为是最佳实践,因为 setter 可以包含比简单更新值更多的逻辑。在只需要存储的情况下,可以去掉该private部分直接更新,不需要setter函数。

您可以在 Compose文档中找到有关状态的更多信息,包括解释基本原理的YouTube 视频。