Перемещение жизненного цикла фрагмента при навигации - PullRequest
0 голосов
/ 03 июля 2018

У меня есть одно Activity приложение с несколькими Fragments, которые переключаются с помощью компонентов навигации. Когда я переключаюсь между двумя фрагментами, их onCreate() и onDestroy() методы, кажется, пересекаются. Это затрудняет мне написание инициализации и очистку кода для фрагментов, когда они получают доступ к одним и тем же глобальным объектам.

Переход от Framgent_A к Fragment_B имеет следующий порядок методов:

Fragment_B.onCreate()
Fragment_A.onDestroy()

В Fragment_A.onDestroy() Я отменяю операции, которые выполняю в Fragment_A.onCreate(). И в Fragment_B я ожидаю, что все будет в нейтральном состоянии, когда вызывается onCreate(). Однако это не так, поскольку Fragment_A.onDestroy() еще не был вызван.

Нормальное перекрытие на Android или я настроил что-то неправильно в моих компонентах навигации? Есть ли другой способ добиться того, что я пытаюсь сделать? Я знаю, что мог бы соединить оба Fragments и заставить это работать, но я не хочу, чтобы Фрагмент знал друг о друге. Мне кажется странным, что Framgnet_A все еще жив, когда создается Fragment_B, когда Fragment_B должен заменить Fragment_A.

Любая помощь очень ценится!


Редактировать:

После просмотра исходного кода во время отладки я обнаружил, что в FragmentNavigator.navigate() FragmentTransaction.setReorderingAllowed () вызывается , что позволяет переупорядочивать операции, даже позволяя onCreate() нового фрагмента быть вызванным до onDestroy() предыдущего. Все еще остается вопрос, как мне решить мою проблему правильной очистки глобального состояния в одном фрагменте перед инициализацией того же глобального состояния в следующем фрагменте.

Ответы [ 3 ]

0 голосов
/ 17 января 2019

Жизненный цикл Android Fragment на самом деле не является подходящим хостом обратного вызова для ваших нужд. Контроллер навигации заменит два фрагмента анимацией, так что оба будут как-то видны одновременно, и в конечном итоге даже onPause() из выходящего фрагмента вызывается после onResume() из входящего.

Решение 1: Использовать OnDestinationChangedListener

Обратный вызов onDestinationChanged() вызывается перед любым из событий жизненного цикла. В качестве очень упрощенного подхода (обратите внимание на утечки) вы можете сделать следующее:

    findNavController().addOnDestinationChangedListener { _, destination, _ ->
        if(shouldCleanupFor(destination)) cleanup()
    }

Решение 2: Абстрагироваться от глобальных изменений

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

findNavController(R.id.nav_graph).addOnDestinationChangedListener { _, destination, _ ->
    resetAll()
    when(distination.id) {
        R.id.fragment_a -> prepareForA()
        R.id.fragment_b -> prepareForB()
        else -> prepareDefault()
    }
}

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

0 голосов
/ 17 января 2019

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

Другой доступный вариант - использование шаблона Observer / Observable , где вы можете уведомить о своей активности, как только onDestroy() во Фрагменте А завершен. Затем действие уведомит фрагмент B о том, что безопасно принять очищенное состояние и начать инициализацию.

0 голосов
/ 14 января 2019

Поскольку у вас есть действие, которое контролирует наполнение ваших фрагментов, вы можете вручную контролировать жизненные циклы раздуваемого фрагмента. Вызывая приведенные ниже методы, вы можете контролировать, какой фрагмент готов к использованию глобальных данных. В этот момент вам нужно будет как-то передать данные обратно в Mainactivity, чтобы установить, какой фрагмент активен, поскольку вы спрашиваете, как раздувать 2 фрагмента одновременно, которые будут совместно использовать объект. Лучшим подходом было бы, чтобы MainActivity реализовывал FragmentA и FragmentB-detail с конкретными классами для выполнения Stuff таким образом, чтобы вы обрабатывали свое приложение как планшет и определяли режим 2 панелей, и в какой момент вы можете использовать соответствующие классы из тех фрагментов, контролируемых вашим Деятельность. Включенная ссылка соответствует тому, что вы пытаетесь выполнить

private void addCenterFragments(Fragment fragment) {
        try {
            removeActiveCenterFragments();
            fragmentTransaction = fragmentManager.beginTransaction();
            fragmentTransaction.add(R.id.content_fragment, fragment);
            fragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
            activeCenterFragments.add(fragment);
            fragmentTransaction.commit();
        }catch (Exception e){
            Crashlytics.logException(e);
        }
    }

    private void removeActiveCenterFragments() {
        if (activeCenterFragments.size() > 0) {
            fragmentTransaction = fragmentManager.beginTransaction();
            for (Fragment activeFragment : activeCenterFragments) {
                fragmentTransaction.remove(activeFragment);
            }
            activeCenterFragments.clear();
            fragmentTransaction.commit();
        }
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...