导航时导航主机变为空(Android导航组件)

时间:2019-06-14 17:42:54

标签: android kotlin android-architecture-components

我正在创建一个游戏,其中用户浏览一系列5个屏幕。在最后一个屏幕上,用户可以选择结束游戏,然后将他们带回到开始屏幕。我的问题出在用户结束游戏然后再次开始时。浏览应用程序时,找不到导航主机片段。

第一次浏览该应用程序,它会照常导航,但第二次,找不到导航主机。

我尝试使用不同的视图来查找导航主机,并且在调试时,我发现对于找不到它的片段,其父级等于null。

这是我浏览的地方,位于片段onViewCreated()

    viewModel.getGameUpdates().observe(activity!!, Observer { updatedGame ->
                if(updatedGame.playerList.size == 0){
                    Log.d("END","END")
                    viewModel.endGame()
                }
                adapter?.players = updatedGame.playerList

                if(updatedGame.started){
                    Navigation.findNavController(view).navigate(R.id.action_waitingFragment_to_gameFragment)
                }
            })

这是用户单击导航回到第一个屏幕的时刻:

     btn_end_game.setOnClickListener {
                viewModel.endGame()
                timer.cancel()
                Navigation.findNavController(view).navigate(R.id.action_gameFragment_to_startFragment)
            }

我的MainActivity包含导航主机片段的布局是:

    <?xml version="1.0" encoding="utf-8"?>
    <FrameLayout
            xmlns:android="http://schemas.android.com/apk/res/android"
            xmlns:tools="http://schemas.android.com/tools"
            xmlns:app="http://schemas.android.com/apk/res-auto"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            tools:context=".MainActivity">


        <fragment
                android:id="@+id/nav_host_fragment"
                android:name="androidx.navigation.fragment.NavHostFragment"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                app:layout_constraintLeft_toLeftOf="parent"
                app:layout_constraintRight_toRightOf="parent"
                app:layout_constraintTop_toTopOf="parent"
                app:layout_constraintBottom_toBottomOf="parent"
                app:defaultNavHost="true"
                app:navGraph="@navigation/nav_graph" />

    </FrameLayout>

我确实意识到,当我想跳回到第一个片段时,我只是在后堆栈的顶部添加内容。我只是对片段如何为空感到迷惑。

以下是nav_graph.xml

    <?xml version="1.0" encoding="utf-8"?>
    <navigation xmlns:android="http://schemas.android.com/apk/res/android"
                xmlns:app="http://schemas.android.com/apk/res-auto"
                android:id="@+id/nav_graph" app:startDestination="@id/startFragment">

        <fragment android:id="@+id/startFragment" android:name="com.dangerfield.spyfall.start.StartFragment"
                  android:label="StartFragment">
            <action android:id="@+id/action_startFragment_to_joinGameFragment" app:destination="@id/joinGameFragment"/>
            <action android:id="@+id/action_startFragment_to_newGameFragment" app:destination="@id/newGameFragment"/>
        </fragment>
        <fragment android:id="@+id/newGameFragment" android:name="com.dangerfield.spyfall.newGame.NewGameFragment"
                  android:label="NewGameFragment">
            <action android:id="@+id/action_newGameFragment_to_waitingFragment" app:destination="@id/waitingFragment"/>
        </fragment>
        <fragment android:id="@+id/joinGameFragment" android:name="com.dangerfield.spyfall.joinGame.JoinGameFragment"
                  android:label="JoinGameFragment">
            <action android:id="@+id/action_joinGameFragment_to_waitingFragment" app:destination="@id/waitingFragment"/>
        </fragment>
        <fragment android:id="@+id/waitingFragment" android:name="com.dangerfield.spyfall.waiting.WaitingFragment"
                  android:label="WaitingFragment">
            <action android:id="@+id/action_waitingFragment_to_gameFragment" app:destination="@id/gameFragment"/>
            <action android:id="@+id/action_waitingFragment_to_startFragment" app:destination="@id/startFragment"/>
        </fragment>
        <fragment android:id="@+id/gameFragment" android:name="com.dangerfield.spyfall.game.GameFragment"
                  android:label="GameFragment">
            <action android:id="@+id/action_gameFragment_to_startFragment" app:destination="@id/startFragment"/>
        </fragment>
    </navigation>

这是崩溃后给出的消息: java.lang.IllegalStateException: View android.widget.ScrollView{637e4ce VFED.V... ......ID 0,0-1440,2308} does not have a NavController set

1 个答案:

答案 0 :(得分:0)

LiveData会记住当前数据,并在观察者再次启动时自动将其重新传送,使其不适合触发导航操作的事件:每次您对navigate()的操作都会被触发片段已启动,实际上无法弹出该片段。

请注意,在上的堆栈中不会破坏碎片。如果要在分片位于后堆栈上时更改分片所依赖的基础数据,则应将viewLifecycleOwner而不是this(代表分片)用于传递给{{ 1}}在observe()中进行观察。这样可以确保一旦视图被破坏(即,进入后堆栈),您将不再获得观察者回调。

onViewCreated()在Fragment中用作LifecycleOwner绝对是错误的,因为这意味着即使Fragment被完全销毁,观察者也不会被清理(它将仅在活动被销毁时进行清理。

根据conditional navigation documentation,推荐的方法是确保LiveData跟踪的是状态而不是事件。这样,在调用activity!!之后,您可以更新状态以确保第二次发生回调时,您不会再次调用navigate()。建议在SingleLiveEvent approach上使用此方法。