簡體   English   中英

導航時導航主機變為空(Android 導航組件)

[英]Navigation Host becomes null while navigating (Android Navigation Component)

我正在創建一個游戲,用戶在其中瀏覽一系列 5 個屏幕。 在最后一個屏幕上,用戶可以選擇結束游戲,此時他們將被帶回起始屏幕。 當用戶結束游戲然后重新開始時,我的問題就出現了。 在應用程序中導航時,找不到導航主機片段。

第一次通過app,正常導航,但是第二次,找不到導航主機。

我嘗試使用不同的視圖來查找導航主機,在調試時,我看到對於找不到它的片段,父級等於空。

這是我導航的地方,在 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

LiveData記住當前的數據,並會在觀察者再次啟動時自動重新傳遞它,這使得它不適用於觸發導航操作的事件:每次您的 Fragment 啟動時都會觸發您對 navigation navigate()操作,因此實際上不可能彈回那個片段。

需要注意的是碎片不會同時后退堆棧摧毀。 如果您正在更改 Fragment 所依賴的基礎數據,而該 Fragment 位於后端堆棧上,則您應該使用viewLifecycleOwner而不是this (代表 Fragment)作為在onViewCreated()觀察時傳遞給observe() LifecycleOwner 。 這確保一旦您的視圖被銷毀(即,您進入返回堆棧),您將不再獲得觀察者回調。

activity!! 在 Fragment 中用作 LifecycleOwner 絕對是錯誤的,因為這意味着即使 Fragment 被完全銷毀,觀察者也不會被清理(它只會在活動被銷毀時被清理)。

根據條件導航文檔,推薦的方法是確保您的 LiveData 跟蹤狀態而不是事件。 這樣,在您調用navigate() ,您可以更新狀態以確保第二次發生回調時,您不會第二次調用navigate() SingleLiveEvent 方法相比,推薦使用此方法

即使我以前從當前片段導航到下一個片段時也面臨同樣的問題,並且在硬件 navHost 的背面按下時會為空,我做的錯誤是我將變量 navController 設為全局變量,我曾經這樣做過在 onCreate() 中像這樣實例化

前:

class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding
    private lateinit var navController: NavController

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
        navController = this.findNavController(R.id.myNavHostFragment)
        NavigationUI.setupActionBarWithNavController(this,navController)
    }

    override fun onSupportNavigateUp(): Boolean {
        return navController.navigateUp()
    }
}

后:

現在它在此更改后工作

class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding
    private lateinit var navController: NavController

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
        navController = this.findNavController(R.id.myNavHostFragment)
        NavigationUI.setupActionBarWithNavController(this,navController)
    }

    override fun onSupportNavigateUp(): Boolean {
        val navController = this.findNavController(R.id.myNavHostFragment)
        return navController.navigateUp()
    }
}

如果將其設為全局,為什么 navController 將為 null?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM