Wie gehe ich mit One-Shot-Operationen in Jetpack Compose um?

Lesezeit: 2 Minuten

Notiz – Diese Frage ist so ziemlich die gleiche wie diese.
Ich suche nach einem besseren Ansatz, falls es einen gibt.

Gem Android-Dokumente,

Sobald die vorübergehende Nachricht angezeigt wurde, muss die Benutzeroberfläche das ViewModel darüber benachrichtigen, was zu einer weiteren Aktualisierung des Benutzeroberflächenstatus führt:

Wenn ich beispielsweise beim Klicken auf eine Schaltfläche eine Toast-Meldung zeige, sollte die Benutzeroberfläche das ViewModel benachrichtigen, dass der Toast erfolgreich angezeigt wurde?
Ist das der beabsichtigte beste Ansatz, um One-Shot-Vorgänge wie Toasts, Snackbar usw. zu handhaben?

Beispielcode,

@Composable
fun OneShotOperation(
    viewmodel: OneShotOperationViewModel = viewModel(),
) {
    val context = LocalContext.current

    LaunchedEffect(
        key1 = viewmodel.toastMessage,
    ) {
        if (viewmodel.toastMessage.isNotBlank()) {
            Toast.makeText(
                context,
                viewmodel.toastMessage,
                Toast.LENGTH_SHORT,
            ).show()
            viewmodel.toastMessage = "" // Is this the correct way?
        }
    }

    Button(
        onClick = {
            viewmodel.toastMessage = "Sample Toast"
        },
    ) {
        Text(text = "Show Toast")
    }
}

class OneShotOperationViewModel : ViewModel() {
    var toastMessage by mutableStateOf(
        value = "",
    )
}

Wenn ich diese Zeile entferne,
viewmodel.toastMessage = "" // Is this the correct way?

Der Toast wird nur einmal angezeigt, der nachfolgende Tastendruck zeigt keinen Toast, da sich der veränderliche Zustand nicht geändert hat.

  • Wenn Sie viewmodel.toastMessage = “” entfernen, können Sie dieselbe Nachricht nicht erneut anzeigen. Und anstatt die Eigenschaften des Ansichtsmodells zu ändern, es soll die entsprechenden Methoden aufrufen, brauchen Sie so etwas wie fun toastShown() {toastMessage = “”} in Ihrem Ansichtsmodell.

    – faul

    8. Februar um 13:43 Uhr

Benutzer-Avatar
Phil Duchov

Ich benutze lieber SharedFlow für so einen Job:

class OneShotOperationViewModel : ViewModel() {
    private val _toastMessage = MutableSharedFlow<String>()
    val toastMessage = _toastMessage.asSharedFlow()

    fun sendMessage(message: String) {
        viewModelScope.launch {
            _toastMessage.emit(message)
        }
    }
}

@Composable
fun TestScreen() {
    val context = LocalContext.current

    val viewModel = viewModel<OneShotOperationViewModel>()
    LaunchedEffect(Unit) {
        viewModel
            .toastMessage
            .collect { message ->
                Toast.makeText(
                    context,
                    message,
                    Toast.LENGTH_SHORT,
                ).show()
            }
    }
    Button(
        onClick = {
            viewModel.sendMessage("Sample Toast")
        },
    ) {
        Text(text = "Show Toast")
    }
}

Beachten Sie, dass, wenn Sie eine Nachricht von einer anderen Ansicht senden, während collect nicht läuft, wird es keinen Toast zeigen, wenn Sie es endlich starten. Er speichert den Wert nicht, sondern gibt ihn nur an alle aktuell angeschlossenen Kollektoren weiter.

1018620cookie-checkWie gehe ich mit One-Shot-Operationen in Jetpack Compose um?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy