jetpack Compose 在 backpress 上实现 "Home button" 功能

jetpack Compose implement "Home button" functionality on backpress

我通过 NavController 进行导航。对于某些目的地,我会像

一样清除堆栈
navController.navigate(nextScreen) { 
    popUpTo(key) { inclusive = true } 
}

当按下系统“后退”按钮时,它会在主屏幕上显示 return。托盘中仍然装有该应用程序,但当我尝试继续使用该应用程序时,main activity 会销毁并重新创建。当按下“系统后退按钮”并且后台堆栈为空时,如何实现“系统主页按钮”等功能? (这意味着不破坏 activity,而只是隐式调用 onPause(),就像它与“系统主页按钮”一起工作一样)

更新

我有一个包含 10 个屏幕的注册流程。由于业务逻辑,在每个屏幕上我都清除了后台堆栈。例如,用户通过了 4/10 的注册流程屏幕。如果他按下主页按钮,应用程序将进入后台,当用户 return 进入应用程序时,它会以与第 5 个屏幕相同的状态打开。但是,如果用户按下后退按钮,当他 return 转到应用程序时,导航将来自 startDestination,即 10 个屏幕中的第一个。我需要像主页按钮一样将应用程序传递到后台。

解决您的问题是 super-easy,几乎不会带来不便。你看,问题不在于 activity 在 back-press 上被清除。这里真正的亮点是 Compose 的机制。不会延长它,简单地说 - 当你按下后退按钮并且你的 activity 被“暂停”时,Composables 被销毁,因为它们不再出现在屏幕上。这就是 Compose 的构建方式(为了性能),它也很有意义。即使您在输入登录凭据的同时导航到应用程序内的另一个屏幕,然后返回登录屏幕,状态也会被清除,因为所有这些可组合项在它们离开的那一刻就被销毁了off-screen。

现在,这就是 ViewModel 应该提供帮助的地方。您可能保存在 Composable 主体中的 TextField 的状态实际上需要保存在 ViewModel 中,它甚至在配置更改时仍然存在,即 [=45] =] 已重新创建,但 ViewModel 会一直存在,直到您的应用程序被终止。所以,只需在 ViewModel 中创建一个值,例如

var userName by mutableStateOf("")

然后将其作为 TextField 的值传递,然后在 onValueChange 中更新它,就像您对 Composable.[=23= 中定义的值所做的那样]

简单,

编辑

实际上 super-easy,几乎没有什么不便——您会看到 Compose 提供了一个 BackHandler 专门用于拦截系统后退按钮。在那里,您可以简单地调用一个意图,它触发一个相当于系统 Home Press 的动作。原意如下:

Intent(Intent.ACTION_MAIN).apply{
 addCategory(Intent.CATEGORY_HOME)
}.let { startActivity(it) }

简单,

感谢@MARSK 的回答。 最后我有这样的东西

    val context = LocalContext.current
    val callback = object: OnBackPressedCallback(
        true
    ) {
        override fun handleOnBackPressed() {
            if (navController.previousBackStackEntry == null) {
                Intent(Intent.ACTION_MAIN).apply{
                    addCategory(Intent.CATEGORY_HOME)
                }.let { context.startActivity(it) }
            } else {
                navController.popBackStack()
            }
        }
    }
    context.getActivity()?.let { activity ->
        val dispatcher = activity.onBackPressedDispatcher
        dispatcher.addCallback(activity, callback)
        navController.setLifecycleOwner(activity)
        navController.setOnBackPressedDispatcher(dispatcher)
    }