Хост навигации становится пустым во время навигации (компонент навигации Android) - PullRequest
0 голосов
/ 14 июня 2019

Я создаю игру, в которой пользователь проходит серию из 5 экранов.На последнем экране пользователь имеет возможность завершить игру, после чего он возвращается на начальный экран.Мои проблемы возникают, когда пользователь заканчивает игру, а затем начинает снова.При навигации по приложению фрагмент хоста навигации не может быть найден.

В первый раз, когда приложение перемещается в обычном режиме, , но во второй раз , хост навигации не может быть найден.

Я пытался использовать разные представления для поиска узла навигации, и во время отладки я обнаружил, что для фрагмента, где его нельзя найти, родительский элемент равен нулю.

Этогде я перемещаюсь, во фрагментах 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 голосов
/ 17 июня 2019

LiveData запоминает текущие данные и автоматически повторно доставляет их при повторном запуске наблюдателя, что делает его неприемлемым для событий, запускающих навигационные операции: ваша операция с navigate() будет запускаться при каждом запуске фрагмента,делая невозможным возвращение к этому фрагменту.

Обратите внимание, что фрагменты не уничтожаются, пока на заднем стеке.Если вы меняете базовые данные, на которые опирается ваш фрагмент, пока этот фрагмент находится в заднем стеке, вы должны использовать viewLifecycleOwner вместо this (представляющий фрагмент) для вашего LifecycleOwner, переданного в observe() при наблюдении вonViewCreated().Это гарантирует, что вы больше не будете получать обратные вызовы наблюдателя после того, как ваше представление разрушено (т. Е. Вы перейдете в задний стек).

activity!! абсолютно всегда неправильно использовать в качестве LifecycleOwner изнутриФрагмент , поскольку это означает, что наблюдатель не будет очищен, даже если фрагмент полностью уничтожен (он будет очищен только после уничтожения действия).

Согласно условию навигационная документация , рекомендуемый подход - убедиться, что ваши LiveData отслеживают состояние , а не события.Таким образом, после вызова navigate() вы можете обновить состояние, чтобы гарантировать, что при повторном вызове вы не вызовете navigate() во второй раз.Этот подход рекомендуется по сравнению с SingleLiveEvent .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...