Jetpack Compose – Wie aktualisiere ich einen Bildschirm, wenn die App in den Vordergrund zurückkehrt?
Lesezeit: 5 Minuten
Wilhelm
Ich muss einen Android Compose-Bildschirm automatisch aktualisieren, wenn die App in den Vordergrund zurückkehrt.
Ich habe eine, die Berechtigungen und Ortungsdienste erfordert.
Wenn der Benutzer eines davon ausgeschaltet hat, wird eine Liste der Elemente erstellt, die geändert werden müssen. Wenn der Benutzer zu Einstellungen geht und die App in den Vordergrund zurückkehrt, möchte ich, dass die Liste aktualisiert wird, um die Änderungen widerzuspiegeln.
Ich verwende die Compose- und Compose-Navigation. Ich habe nachgesehen und kann das Äquivalent des onResume-Lebenszyklusereignisses nicht herausfinden, das zum Auslösen der Aktualisierung verwendet werden könnte.
Irgendwelche Ideen würden dankbar angenommen, da ich ratlos bin.
JojoIV
Ich bin darauf gekommen:
@Composable
fun OnLifecycleEvent(onEvent: (owner: LifecycleOwner, event: Lifecycle.Event) -> Unit) {
val eventHandler = rememberUpdatedState(onEvent)
val lifecycleOwner = rememberUpdatedState(LocalLifecycleOwner.current)
DisposableEffect(lifecycleOwner.value) {
val lifecycle = lifecycleOwner.value.lifecycle
val observer = LifecycleEventObserver { owner, event ->
eventHandler.value(owner, event)
}
lifecycle.addObserver(observer)
onDispose {
lifecycle.removeObserver(observer)
}
}
}
Es scheint gut zu funktionieren. In manchen Fällen kann es jedoch zu Problemen kommen, seien Sie also vorsichtig.
Es ist auch möglich, dass es einen redundanten Code gibt.
Verwendung:
OnLifecycleEvent { owner, event ->
// do stuff on event
when (event) {
Lifecycle.Event.ON_RESUME -> { /* stuff */ }
else -> { /* other stuff */ }
}
}
Ein Anwendungsbeispiel wäre hilfreich
– SagaRock101
1. Januar 2022 um 13:46 Uhr
Warum lifecycleOwner muss sich ändern? Ist etw nicht schreibgeschützt?
– stdout
4. Juli 2022 um 8:22 Uhr
In der Produktion haben wir einige Schleifenprobleme in onResume() beobachtet. dh es ruft den Block Lifecycle.Event.ON_RESUME -> { /* stuff */ } in Schleifen auf
– Boobalan
7. Februar um 18:56 Uhr
Arsenius
Ich habe mich leicht verbessert @JojoIV Antwort und machte es flach Verwendung ohne Rückruf, wie Sie beobachten LiveData in komponieren was @Abdelilah El Aissaoui antwortete
@Composable
fun Lifecycle.observeAsState(): State<Lifecycle.Event> {
val state = remember { mutableStateOf(Lifecycle.Event.ON_ANY) }
DisposableEffect(this) {
val observer = LifecycleEventObserver { _, event ->
state.value = event
}
[email protected](observer)
onDispose {
[email protected](observer)
}
}
return state
}
und dann Nutzung
@Composable
fun SomeComposable() {
val lifecycleState = LocalLifecycleOwner.current.lifecycle.observeAsState()
val state = lifecycleState.value
// or val lifecycleState by LocalLifecycleOwner.current.lifecycle.observeAsState()
// will re-render someComposable each time lifecycleState will change
}
Diese Antwort war nützlich, wenn nur Resume und Pause verwendet wurden, aber nicht Start und Stop.
– Bam Bam
8. November 2022 um 5:44 Uhr
@bambam warum ist das so?
– Josua König
17. November 2022 um 21:50 Uhr
Drucken (die state vor der Rückkehr) und (die event von LifecycleEventObserver) im ersten Ausschnitt . In meinem Fall hieß ersteres nur RESUME und PAUSE. Ich bin mir nicht sicher, aber es scheint, dass es eine Auslassung gibt, indem der Compose-Zustand durchlaufen wird, anstatt das Ereignis sofort zu übergeben. Wenn es sich nicht reproduziert, werde ich weitere Tests durchführen. @JoshuaKing
– Bam Bam
18. November 2022 um 2:39 Uhr
Beispiel von der Google-Website
@Composable
fun HomeScreen(
lifecycleOwner: LifecycleOwner = LocalLifecycleOwner.current,
onStart: () -> Unit, // Send the 'started' analytics event
onStop: () -> Unit // Send the 'stopped' analytics event
) {
// Safely update the current lambdas when a new one is provided
val currentOnStart by rememberUpdatedState(onStart)
val currentOnStop by rememberUpdatedState(onStop)
// If `lifecycleOwner` changes, dispose and reset the effect
DisposableEffect(lifecycleOwner) {
// Create an observer that triggers our remembered callbacks
// for sending analytics events
val observer = LifecycleEventObserver { _, event ->
if (event == Lifecycle.Event.ON_START) {
currentOnStart()
} else if (event == Lifecycle.Event.ON_STOP) {
currentOnStop()
}
}
// Add the observer to the lifecycle
lifecycleOwner.lifecycle.addObserver(observer)
// When the effect leaves the Composition, remove the observer
onDispose {
lifecycleOwner.lifecycle.removeObserver(observer)
}
}
/* Home screen content */
}
Verwendung der offiziellen API (erfordert Lifecycle Runtime Compose 2.7.0):
Warnung: Zum Zeitpunkt des Schreibens (16. März 2023) wurde Lifecycle Runtime Compose 2.7.0 noch nicht veröffentlicht, aber die Änderungen sind bereits im Quellcode enthalten.
Der offizielle Weg zur Erkennung Lifecycle.State Änderungen würden das folgende Code-Snippet verwenden:
val lifecycleOwner = LocalLifecycleOwner.current
val state by lifecycleOwner.lifecycle.collectStateAsState()
LaunchedEffect(state) {
// Do something with your state
// You may want to use DisposableEffect or other alternatives
// instead of LaunchedEffect
}
collectStateAsState ist eine praktische Erweiterungsfunktion, die Zustandsänderungen mithilfe der neuen Eigenschaft von Lifecycle erfasst currentStateFlow. Der obige Code wäre also der gleiche wie:
val lifecycleOwner = LocalLifecycleOwner.current
val state by lifecycleOwner.lifecycle.currentStateFlow.collectAsState()
LaunchedEffect(state) {
// Do something with your state
// You may want to use DisposableEffect or other alternatives
// instead of LaunchedEffect
}
Denken Sie daran, zu importieren androidx.compose.runtime.getValue Zu direkt zugreifen Die Lifecycle.State.
Alte Antwort:
Compose kennt keine Zustandsänderungen wie onPause oder onResumemüssen Sie es mit den Methoden der übergeordneten Aktivität handhaben.
Ein Beispiel wäre a LiveData Instanz in Ihrer Aktivität, die jedes Mal aktualisiert wird onResume ausgeführt wird, und beobachten Sie es als Zustand in Ihrem wichtigsten übergeordneten Composable.
Schauen wir uns das folgende Beispiel an:
class MainActivity : AppCompatActivity() {
// Use whatever type your prefer/require, this is just an example
private val exampleLiveData = MutableLiveData("")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
// Your main composable
MyApplicationTheme {
// Save the state into a variable otherwise it won't work
val state = exampleLiveData.observeAsState()
Log.d("EXAMPLE", "Recomposing screen - ${state.value}")
Surface(color = MaterialTheme.colors.background) {
Greeting("Android")
}
}
}
}
override fun onResume() {
super.onResume()
// Save whatever you want in your live data, this is just an example
exampleLiveData.value = DateTimeFormatter.ISO_INSTANT.format(Instant.now())
}
}
@Composable
fun Greeting(name: String) {
Text(text = "Hello $name!")
}
@Preview(showBackground = true)
@Composable
fun DefaultPreview() {
MyApplicationTheme {
Greeting("Android")
}
}
Wie Sie in diesem Beispiel sehen können, habe ich eine LiveData Eigenschaft in meiner Aktivität, die einen String enthält. Wann auch immer onResume ausgeführt wird, wird die Eigenschaft mit dem neuen Zeitstempel aktualisiert und das beobachtende Composable wird neu zusammengesetzt.
EunhaEonnie
ich habe mich verändert @ojoIV Code dazu (wenn Ihr zusammensetzbarer Code in Aktivität ist)
@Composable
fun ComponentActivity.LifecycleEventListener(event: (Lifecycle.Event) -> Unit) {
val eventHandler by rememberUpdatedState(newValue = event)
val lifecycle = [email protected]
DisposableEffect(lifecycle) {
val observer = LifecycleEventObserver { _, event ->
eventHandler(event)
}
lifecycle.addObserver(observer)
onDispose {
lifecycle.removeObserver(observer)
}
}
}