Получить родительскую активность в подклассе DialogFragment перед show ()

Я работаю над приложением для Android с множеством диалогов, каждый из которых расширяет настраиваемый класс DialogFragmentBase, расширяющий библиотеку DialogFragment. Все действия используют метод show (), переопределенный в DialogFragmentBase.

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

if (getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.RESUMED))

Поэтому я хотел сделать что-то подобное в DialogFragmentBase:

@Override
public void show(FragmentManager manager, String tag){

    List<Fragment> fragments = manager.getFragments();
    if (fragments != null && fragments.size() > 0){
        FragmentActivity activity = fragments.get(fragments.size()-1).getActivity();
        if (activity != null && activity.getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.RESUMED)){
            super.show(manager, tag);
        }
    }
}

Итак, мой вопрос: считается ли такой доступ к предыдущему фрагменту плохой практикой? Это действительно работает ... но я помню, как где-то читал, что фрагменты не должны сообщаться между собой. Если это действительно плохая практика, какое было бы лучшее решение, которое можно было бы реализовать в DialogFragmentBase (чтобы не добавлять повсюду охранников).

Примечание. Я пробовал решение onSaveInstanceState, описанное здесь, но поскольку DialogFragment еще не был показан, onSaveInstanceState в этот момент для него не вызывается. Также getActivity () возвращает null, поскольку onAttach еще не был вызван.

Спасибо!

1
0
614
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Возможно, вы могли бы создать новый метод в своем базовом классе диалогового окна:

public void showIfResumed(FragmentActivity activity, String tag) {
    if (/* your check here, e.g. activity.getLifecycle()...  */) {
        show(activity.getSupportFragmentManager(), tag);
    }
}

И затем, в своей деятельности, вместо того, чтобы звонить show(getSupportFragmentManager(), TAG), вы могли бы звонить showIfResumed(this, TAG). Вам все равно придется менять каждый вызов show() на вызов showIfResumed(), но это значительно уменьшит дублирование кода.

спасибо, это был мой следующий вариант, но является ли решение доступа к списку фрагментов плохой практикой? потому что это позволяет мне ничего не менять в DialogFragmentBase. В то время как с вашим решением мне пришлось бы многое изменить, и я надеюсь на решение, которое можно легко реализовать, вместо того, чтобы зависеть от разработчиков, вызывающих showIfResumed, что не является интуитивно понятным.

Menna Mostafa 09.08.2018 21:24

@MennaMostafa Я бы сказал, да, то, что вы разместили в своем вопросе, является плохой практикой. Почему ваш фрагмент опрашивает диспетчер фрагментов о других фрагментах, которыми он управляет? Что будет, если нет «предыдущего» фрагмента? Что произойдет, если «предыдущий» фрагмент не привязан к действию? И т. Д. Вы потенциально можете изменить существующий метод show() в базовом классе, чтобы выбросить UnsupportedOperationException, чтобы любой, кто его использовал, сразу понял, что этого не следует делать.

Ben P. 09.08.2018 21:28
Ответ принят как подходящий

библиотека поддержки FragmentManager имеет isStateSaved() метод. В зависимости от того, какие именно ваши требования, вы можете использовать это, чтобы проверить, «безопасно» ли показывать ваши диалоги:

@Override
public void show(FragmentManager manager, String tag) {
    if (!manager.isStateSaved()) {
        super.show(manager, tag);
    }
}

Обратите внимание, что приведенная выше реализация относительно похожа на использование commitAllowingStateLoss(), поскольку в некоторых случаях вы молча не сможете отобразить свой диалог. Но, возможно, это подходит для ваших требований.

isStateSaved () возвращает false, даже если родительская активность уже находится в фоновом режиме. Я начинаю думать, что, возможно, commitAllowingStateLoss() не такой уж плохой подход (по крайней мере, в моем случае, поскольку диалоговое окно, которое я хочу показать пользователю, бесполезно, если приложение все равно находится в фоновом режиме).

Menna Mostafa 09.08.2018 22:02

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

Ben P. 09.08.2018 22:05

Действительно? это не то, что я вижу, я получаю illegalStateException. Может быть, потому, что я использую show(), а не commitNow(), поэтому к тому времени, когда шоу запланировано, состояние уже было сохранено?

Menna Mostafa 09.08.2018 22:11

Предполагая, что вы получаете исключение для can not be performed after onSaveInstanceState(), тогда да. Важно то, сохранил ли менеджер фрагментов свое состояние; если нет, то любая транзакция безопасна. Но вы правы, я могу полагать, что есть сценарии, в которых можно добавить транзакцию в очередь, а затем диспетчер фрагментов сохранить свое состояние до обработки этой транзакции.

Ben P. 09.08.2018 22:20

Так что мне удалось заставить его работать, выполнив следующие действия: if (! Manager.isStateSaved () &&! SavedInstanceStateDone) {transaction.commitNow (); } Это нормально?

Menna Mostafa 10.08.2018 17:26

Мне кажется разумным

Ben P. 10.08.2018 18:30

Другие вопросы по теме