Фрагмент уничтожается и создается, когда это не предполагается, при использовании компонентов архитектуры Android.

У меня есть немного doozie. У меня есть игровое приложение с 3 фрагментами. Фрагмент A, фрагмент B, фрагмент C с использованием живых данных и компонента навигации от Google. Когда пользователь завершает работу с фрагментом C, я использую компонент навигации, чтобы вывести задний стек обратно к фрагменту A.

первая проблема: когда я извлекаю задний стек, вызывается onDestroy() этого фрагмента. У меня сложилось впечатление, что это не должно происходить через этот пост: /а>.

вторая проблема: как только пользователь возвращается к фрагменту A, есть возможность перейти к фрагменту B. Как только строка вызывается для навигации, каким-то образом фрагмент C добавляется в задний стек, и создается представление, в результате чего мое приложение к сбою, так как у меня есть слушатель, прослушивающий переменную в моей модели представления, которая используется совместно между фрагментами, установленными во фрагменте B.

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

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

Учитывая, что это код внутри наблюдателя, который разбил мое приложение, я также пытался добавить наблюдателя только в onResume() и отсоединить его в onDestroy(), однако, когда фрагмент воссоздается, он проходит через onResume() и просто прикрепляется наблюдатель сразу

Навигация от фрагмента А к фрагменту Б

 viewModel.addPlayer(asPlayer).addOnCompleteListener {
            Log.d("Game", "current destination before joining: "+resources.getResourceEntryName(navController.currentDestination!!.id))
            navController.navigate(R.id.action_joinGameFragment_to_waitingFragment)
        }

Вызов Observer приводит к сбою.

 //so this observer is not getting detached, maybe manually detach it and reattach it in on resume
        viewModel.gameExists.observe(this, androidx.lifecycle.Observer { exists ->
            //someone ended the game
            var debug = navController
            if(!exists && navController.currentDestination?.id == R.id.gameFragment){ endGame() }
        })

функция, которая дала сбой

 fun endGame(){
        viewModel.endGame()
        Log.d("Game", "current destination before crash: "+resources.getResourceEntryName(navController.currentDestination!!.id))
        timer.cancel()
        Log.d("Game", "current destination before poping: "+resources.getResourceEntryName(navController.currentDestination!!.id))
        navController.popBackStack(R.id.startFragment, false)
        Log.d("Game", "current destination after poping: "+resources.getResourceEntryName(navController.currentDestination!!.id))

    }

результаты из журнала cat

2019-06-16 20:13:40.278 13021-13021/com.dangerfield.spyfall D/Game: current destination before poping:  (FRAGMENT C)
2019-06-16 20:13:40.279 13021-13021/com.dangerfield.spyfall D/Game: current destination after poping: (FRAGMENT A)
2019-06-16 20:13:40.279 13021-13021/com.dangerfield.spyfall D/View Model: game =  null
2019-06-16 20:13:40.299 13021-13021/com.dangerfield.spyfall D/GAME: ON DESTROY
2019-06-16 20:13:40.315 13021-13021/com.dangerfield.spyfall D/View Model: game =  null
2019-06-16 20:14:05.289 13021-13021/com.dangerfield.spyfall D/Game: current destination before joining: (FRAGMENT A)
2019-06-16 20:14:05.316 13021-13021/com.dangerfield.spyfall D/Game: on Create
2019-06-16 20:14:05.317 13021-13021/com.dangerfield.spyfall D/Game: onCreateView
2019-06-16 20:14:05.353 13021-13021/com.dangerfield.spyfall D/GAME: ON RESUME
2019-06-16 20:14:05.353 13021-13021/com.dangerfield.spyfall D/Game: current destination before crash: (FRAGMENT C)
019-06-16 20:14:05.359 13021-13021/com.dangerfield.spyfall E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.dangerfield.spyfall, PID: 13021
    kotlin.UninitializedPropertyAccessException: lateinit property timer has not been initialized
        at com.dangerfield.spyfall.game.GameFragment.endGame(GameFragment.kt:158)

(фрагмент игры - фрагмент C)

Любая помощь/направление будет принята с благодарностью, большое спасибо.


person Eli Dangerfield    schedule 17.06.2019    source источник
comment
Фрагменты всегда уничтожаются, когда они извлекаются из заднего стека.   -  person ianhanniballake    schedule 17.06.2019
comment
@ianhanniballake спасибо за ответ, чувак. Не могли бы вы указать мне направление какой-нибудь документации, которая поможет мне узнать об этом поведении? Я не мог найти это нигде. Кроме того, даже если фрагмент будет уничтожен, нет смысла снова добавлять его в задний стек и возобновлять, не сделав этого.   -  person Eli Dangerfield    schedule 17.06.2019
comment
См. мой ответ на другой вопрос. Вам нужно исправить свои observe() звонки.   -  person ianhanniballake    schedule 17.06.2019