Android - Как закрыть все диалоги в onPause

У меня есть действие, которое может отображать разные диалоги во время выполнения. Я использую onCreateDialog (int id) для создания каждого диалогового окна, а также использую методы showDialog (int id) и dismissDialog (int id) для отображения и закрытия каждого диалогового окна соответственно.

Когда вызывается onPause (), я не знаю, какой диалог (если есть) отображается. Я хочу убедиться, что при вызове onPause все диалоги затемняются. Есть ли рекомендуемый способ закрыть все диалоги? Придется ли мне вызывать dismissDialog () для каждого диалога?


person AndyB    schedule 08.02.2012    source источник


Ответы (5)


В зависимости от того, о каком количестве диалогов мы говорим. Короткий ответ - да, вам придется закрыть каждый диалог.

Могут быть изящные способы сделать это, кроме простого объявления нескольких диалогов на уровне активности. Вы можете сохранить все диалоги в HashMap после их объявления, а затем выполнить итерацию по списку и закрыть каждый из них onPause.

Поскольку вы не знаете, какие из них открыты, вам необходимо пройти и протестировать или отслеживать состояния.

Однако, если у вас действительно так много диалогов на экране, у вас могут возникнуть проблемы с дизайном UI / UX, поскольку Android должен предоставить вам модель, которая упрощает реализацию без того, что кажется плохим дизайном.

person mhradek    schedule 08.02.2012
comment
Кроме того, чтобы избежать ошибок при закрытии закрытых диалоговых окон, вы можете использовать команду try-catch каждый раз, когда закрываете диалоговое окно. Это намного проще кодировать, чем проверять наличие открытых диалоговых окон. - person Arci; 09.02.2012

Если вы используете DialogFragment и хотите закрыть все, что можете использовать:

/**
 * Dismiss all DialogFragments added to given FragmentManager and child fragments
 */
public static void dismissAllDialogs(FragmentManager manager) {
    List<Fragment> fragments = manager.getFragments();

    if (fragments == null)
        return;

    for (Fragment fragment : fragments) {
        if (fragment instanceof DialogFragment) {
            DialogFragment dialogFragment = (DialogFragment) fragment;
            dialogFragment.dismissAllowingStateLoss();
        }

        FragmentManager childFragmentManager = fragment.getChildFragmentManager();
        if (childFragmentManager != null)
            dismissAllDialogs(childFragmentManager);
    }
}
person Dominik Suszczewicz    schedule 20.05.2015
comment
Похоже, что это самое чистое решение для DialogFragment. Вы используете его в своих производственных приложениях? - person ar-g; 17.07.2015
comment
childFragmentManager имеет значение NonNull, поэтому проверка не требуется - person Leo Droidcoder; 30.05.2018
comment
getFragments () при необходимости вернет пустой список, поэтому проверка на null не требуется. - person hulius; 02.08.2018

Поскольку в последнее время Android делает упор на использование контейнера DialogFragment, вам не понадобится призывать увольнять по каждому

Поскольку в диалоговых окнах есть контейнер фрагментов, вы можете просто использовать их жизненный цикл. Рассмотрим этот DialogFragment:

public class FragDialog extends DialogFragment{

    public ProgressDialog _dialog;

    @Override
    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        if (savedInstanceState != null) {
            //this.dismiss();     <-- The dialogs may be dismissed here
        }
    }

    @Override
    public Dialog onCreateDialog(final Bundle savedInstanceState) {

        _dialog = new ProgressDialog(getActivity());
        return _dialog;
    }

    @Override
    public void onPause() {
        super.onPause();
        // <--------- You may overload onPause
    }
}

Что вы будете показывать в своей деятельности, используя диспетчер фрагментов, обычно называя это так:

FragmentManager fm = getSupportFragmentManager();
FragDialog fragDialog = new FragDialog();
fragDialog.show(fm, "my_tag");

Обратите внимание, что вы можете изменить то, что DialogFragment делает в onPause. Когда ваше действие вызывает onPause, этот onPause также будет вызываться.

Отказ от диалога в onPause () с помощью this.dismiss () не будет работать, потому что после возобновления действия он также возобновит диалог. (Я думаю, это потому, что сохранение сохраняется до onPause).

Но вы можете безопасно закрыть диалоговые окна в onCreate, если вы обнаружите сохраненное состояние экземпляра (резюме), как показано в коде.

person quinestor    schedule 19.10.2012
comment
Это отличное решение, которое все еще работает в 2018 году, спасибо! - person Micer; 14.02.2018

У меня есть другое решение, это могло бы быть хорошо. Вы только установили расширение своего настраиваемого диалогового окна до этого SiblingDialog, которое подпишет ваш Dialog на широковещательное событие закрытия диалогов. Таким образом, вы можете отправить трансляцию куда угодно, и все SiblingDialogs будут закрыты.

В этом примере метод диалогового окна отмены и отклонения был переопределен, поэтому сам SiblingDialog закрывает всех остальных братьев и сестер при закрытии.

public class SiblingDialog extends Dialog {

    protected LocalBroadcastManager mLocalBroadcastManager;

    protected BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            switch (intent.getAction()) {
                case "CLOSE_ALL_DIALOGS":
                    if (isShowing()) {
                        dismiss();
                    }
                    break;
                default:
                    break;
            }
        }
    };
    String[] ACTIONS_LIST = {"CLOSE_ALL_DIALOGS"};

    public SiblingDialog(Context context) {
        super(context);
    }

    public SiblingDialog(Context context, int themeResId) {
        super(context, themeResId);
    }


    public SiblingDialog(Context context, boolean cancelable, OnCancelListener cancelListener) {
        super(context, cancelable, cancelListener);
    }

    private void registerTheBroadCast() {
        mLocalBroadcastManager = LocalBroadcastManager.getInstance(getContext());
        IntentFilter mIntentFilter = new IntentFilter();
        for (String actions : ACTIONS_LIST) {
            mIntentFilter.addAction(actions);
        }
        mLocalBroadcastManager.registerReceiver(mBroadcastReceiver, mIntentFilter);
    }

    private void unregisterBroadCast() {
        mLocalBroadcastManager.unregisterReceiver(mBroadcastReceiver);
    }

    @Override
    public void show() {
        registerTheBroadCast();
        super.show();
    }

    @Override
    public void cancel() {
        unregisterBroadCast();
        mLocalBroadcastManager.sendBroadcast(newIntent("CLOSE_ALL_DIALOGS"));
        super.cancel();

    }

    @Override
    public void dismiss() {
        unregisterBroadCast();
        mLocalBroadcastManager.sendBroadcast(new Intent("CLOSE_ALL_DIALOGS"));
        super.dismiss();
    }
}
person Eduardo Luttinger    schedule 17.06.2019
comment
Отличное решение, спасибо - person Văn Tăng Lê; 05.02.2021

В Kotlin вы можете сделать это намного проще.

Если вы хотите закрыть все DialogFragments:

    private fun dismissDialogs() {
        supportFragmentManager.fragments.takeIf { it.isNotEmpty() }
                ?.map { (it as? DialogFragment)?.dismiss() }
    }

Если вы хотите закрыть все DialogFragments, кроме одного:

    private fun dismissDialogs(fragment: DialogFragment) {
        supportFragmentManager.fragments.takeIf { it.isNotEmpty() }
                ?.map { if (it != fragment) (it as? DialogFragment)?.dismiss() }
    }
person Matthew Strukov    schedule 08.03.2020