Jetpack compose - 当应用程序返回前台时如何刷新屏幕

Wil*_*iam 4 android android-lifecycle android-jetpack-compose

当应用程序返回到前台时,我需要自动刷新 Android Compose 屏幕。

我有一个需要权限和位置服务的。

如果用户关闭了其中的任何一个,则会绘制一个包含需要更改的项目的列表。当用户转到“设置”并且应用程序返回到前台时,我希望刷新列表以反映更改。

我正在使用 Compose 和 Compose 导航。我已经看过了,但无法弄清楚可用于触发刷新的 onResume 生命周期事件的等效项。

任何想法将不胜感激,因为我不知所措。

Ars*_*ius 52

我稍微改进了@JojoIV 的答案,并使其扁平化使用,无需回调,就像您LiveData在撰写@Abdelilah El Aissaoui回答的内容中观察到的那样

@Composable
fun Lifecycle.observeAsState(): State<Lifecycle.Event> {
    val state = remember { mutableStateOf(Lifecycle.Event.ON_ANY) }
    DisposableEffect(this) {
        val observer = LifecycleEventObserver { _, event ->
            state.value = event
        }
        this@observeAsState.addObserver(observer)
        onDispose {
            this@observeAsState.removeObserver(observer)
        }
    }
    return state
}
Run Code Online (Sandbox Code Playgroud)

然后使用

@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
}
Run Code Online (Sandbox Code Playgroud)


Abd*_*oui 47

使用官方 API(需要 Lifecycle Runtime Compose 2.7.0):

\n
implementation("androidx.lifecycle:lifecycle-runtime-compose:2.7.0")\n
Run Code Online (Sandbox Code Playgroud)\n

检测更改的官方方法Lifecycle.State是使用以下代码片段:

\n
val lifecycleOwner = LocalLifecycleOwner.current\nval lifecycleState by lifecycleOwner.lifecycle.currentStateFlow.collectAsState()\n\nLaunchedEffect(lifecycleState) {\n    // Do something with your state\n    // You may want to use DisposableEffect or other alternatives\n    // instead of LaunchedEffect\n    when (lifecycleState) {\n        Lifecycle.State.DESTROYED -> {}\n        Lifecycle.State.INITIALIZED -> {}\n        Lifecycle.State.CREATED -> {}\n        Lifecycle.State.STARTED -> {}\n        Lifecycle.State.RESUMED -> {}\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

collectStateAsState是一个方便的扩展函数,它通过使用 Lifecycle 的新属性来收集 State 更改currentStateFlow。所以上面的代码与执行相同:

\n
val lifecycleOwner = LocalLifecycleOwner.current\nval state by lifecycleOwner.lifecycle.currentStateFlow.collectAsState()\n\nLaunchedEffect(state) {\n    // Do something with your state\n    // You may want to use DisposableEffect or other alternatives \n    // instead of LaunchedEffect\n}\n
Run Code Online (Sandbox Code Playgroud)\n

请记住导入androidx.compose.runtime.getValue直接访问Lifecycle.State.

\n

正如 @H\xc3\xa5konSchia 所提到的,您还可以使用 DiposableEffect 的变体,这些变体也考虑了生命周期:

\n
LifecycleStartEffect(Unit) {\n    // Do something on start or launch effect\n\n    onStopOrDispose {\n        // Do something on stop or dispose effect\n    }\n}\n\nLifecycleResumeEffect(Unit) {\n    // Do something on resume or launch effect\n\n    onPauseOrDispose {\n        // Do something on pause or dispose effect\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

旧答案:

\n

Compose 不知道状态更改,例如onPauseonResume,您必须使用父活动的方法来处理它。

\n

一个示例是LiveData您的活动中的一个实例,每次onResume执行时都会更新,并将其作为主要父可组合项中的状态进行观察。

\n

让我们看一下下面的例子:

\n
class MainActivity : AppCompatActivity() {\n    // Use whatever type your prefer/require, this is just an example\n    private val exampleLiveData = MutableLiveData("")\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        setContent {\n            // Your main composable\n            MyApplicationTheme {\n                // Save the state into a variable otherwise it won\'t work\n                val state = exampleLiveData.observeAsState()\n                Log.d("EXAMPLE", "Recomposing screen - ${state.value}")\n\n                Surface(color = MaterialTheme.colors.background) {\n                    Greeting("Android")\n                }\n            }\n        }\n    }\n\n    override fun onResume() {\n        super.onResume()\n\n        // Save whatever you want in your live data, this is just an example\n        exampleLiveData.value = DateTimeFormatter.ISO_INSTANT.format(Instant.now())\n    }\n}\n\n@Composable\nfun Greeting(name: String) {\n    Text(text = "Hello $name!")\n}\n\n@Preview(showBackground = true)\n@Composable\nfun DefaultPreview() {\n    MyApplicationTheme {\n        Greeting("Android")\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

正如您在此示例中看到的,LiveData我的活动中有一个包含字符串的属性。每当onResume执行时,属性都会使用新的时间戳进行更新,并且观察可组合项会被重构。

\n

  • 似乎 2.7.0 还包括像 `LifecycleStartEffect()` 和 `LifecycleResumeEffect()` 这样的便利函数 https://github.com/androidx/androidx/blob/androidx-main/lifecycle/lifecycle-runtime-compose/src/main /java/androidx/lifecycle/compose/LifecycleEffect.kt (2认同)

Эва*_*ist 27

来自谷歌网站的示例

@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 */
}
Run Code Online (Sandbox Code Playgroud)

谷歌网站上对其工作原理的完整描述 https://developer.android.com/jetpack/compose/side-effects#disposableeffect


Joj*_*ojo 9

我也需要这个,但什么也没找到。然后我想出了这个:

@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)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

它似乎工作得很好。但在某些情况下可能会出现一些问题,所以要小心。
也有可能存在一些冗余代码。

  • 有关如何使用它的示例会很有帮助 (5认同)
  • 为什么“lifecycleOwner”必须改变?它不是只读的吗? (2认同)
  • 在生产中,我们确实在 onResume() 中观察到一些循环问题。即它不断循环调用 Lifecycle.Event.ON_RESUME -&gt; { /* stuff */ } 块 (2认同)

tas*_*apr 9

这是 2023 年的解决方案

创建效用函数:

@Composable
fun rememberLifecycleEvent(lifecycleOwner: LifecycleOwner = LocalLifecycleOwner.current): Lifecycle.Event {
    var state by remember { mutableStateOf(Lifecycle.Event.ON_ANY) }
    DisposableEffect(lifecycleOwner) {
        val observer = LifecycleEventObserver { _, event ->
            state = event
        }
        lifecycleOwner.lifecycle.addObserver(observer)
        onDispose {
            lifecycleOwner.lifecycle.removeObserver(observer)
        }
    }
    return state
}
Run Code Online (Sandbox Code Playgroud)

在您的屏幕可组合项中使用它:

val lifecycleEvent = rememberLifecycleEvent()
LaunchedEffect(lifecycleEvent) {
     if (lifecycleEvent == Lifecycle.Event.ON_RESUME) {
        // initiate data reloading
     }
}
Run Code Online (Sandbox Code Playgroud)

来源:Jetpack Compose 与生命周期感知可组合项