重新创建 activity 后以编程方式设置导航图时,显示错误的片段

When setting navigation graph programmatically after recreating activity, wrong fragment is shown

我正在以编程方式设置导航图,以根据某些条件(例如,活动会话)设置起始目的地,但是当我在启用“不保留活动”选项的情况下对此进行测试时,我遇到了以下错误.

当 activity 刚刚重新创建并且应用程序调用方法 NavController.setGraph 时,NavController 强制恢复导航返回堆栈(从 onGraphCreated 方法中的内部字段 mBackStackToRestore),即使起始目的地与之前不同所以用户看到了错误的片段。

这是我的 MainActivity 代码:

class MainActivity : AppCompatActivity() {

    lateinit var navController: NavController
    lateinit var navHost: NavHostFragment

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.main_activity)
        log("fresh start = ${savedInstanceState == null}")
        navHost = supportFragmentManager.findFragmentById(R.id.main_nav_host) as NavHostFragment
        navController = navHost.navController
        createGraph(App.instance.getValue())
    }

    private fun createGraph(bool: Boolean) {
        Toast.makeText(this, "Is session active: $bool", Toast.LENGTH_SHORT).show()
        log("one: ${R.id.fragment_one}, two: ${R.id.fragment_two}")
        val graph =
            if (bool) {
                log("fragment one")
                navController.navInflater.inflate(R.navigation.nav_graph).also {
                    it.startDestination = R.id.fragment_one
                }
            } else {
                log("fragment two")
                navController.navInflater.inflate(R.navigation.nav_graph).also {
                    it.startDestination = R.id.fragment_two
                }
            }
        navController.setGraph(graph, null)
    }
}

应用代码:

class App : Application() {
    companion object {
        lateinit var instance: App
    }

    private var someValue = true
    override fun onCreate() {
        super.onCreate()
        instance = this
    }

    fun getValue(): Boolean {
        val result = someValue
        someValue = !someValue
        return result
    }
}

片段一和片段二只是空片段。

它的样子:

包含完整代码和更多解释的存储库 link

我的问题:是导航库错误还是我做错了什么?也许我使用的方法不好,有更好的方法可以实现我想要的?

正如您在存储库中尝试的那样,它来自 save/restoreInstanceState。

这意味着您通过 createGraph(App.instance.getValue())onCreate 中设置了 suit graph,然后 onRestoreInstanceState 中的 fragmentManager 将覆盖您对 NavHostFragment 的配置。

因此您可以将onRestoreInstanceState中的图表设置为另一个时间。但它不会工作,因为 this line 并且 backstack 不为​​空。 (我认为这种行为可能是一个错误...)

因为你在不同的情况下使用图表 (R.navigation.nav_graph) 并且只是改变他们的 startDestination,你可以确定在进程死亡后,使用的图表是你的需求图表。所以只需在 onRestoreInstanceState.

中覆盖 startDestination
override fun onRestoreInstanceState(savedInstanceState: Bundle) {
    super.onRestoreInstanceState(savedInstanceState)

    if (codition) {
        navController.graph.startDestination = R.id.fragment_one
    } else {
        navController.graph.startDestination = R.id.fragment_two
    }
}

看起来库中有一些错误行为,我的方法也不是 100% 正确。至少,有更好的,而且效果很好。 因为我使用的是相同的图表并且只更改了起始目的地,所以我可以简单地在 activity 的 onCreate 中设置该图表并在那里设置一些默认的起始目的地。然后,在 createGraph 方法中,我可以执行以下操作:

    // pop backStack while it is not empty
    while (navController.currentBackStackEntry != null) {
        navController.popBackStack()
    }
    // then just navigate to desired destination with additional arguments if needed
    navController.navigate(destinationId, destinationBundle)