Zapobiegaj zwolnieniu okna dialogowego podczas obracania ekranu w systemie Android

Próbuję zapobiec odrzuceniu okien dialogowych zbudowanych za pomocą programu Alert builder po ponownym uruchomieniu aktywności.

Jeśli przeciążę metodę onConfigurationChanged mogę to z powodzeniem zrobić i zresetować układ, aby poprawić orientację, ale tracę funkcję lepkiego tekstu edittext. Tak więc w rozwiązywaniu problemu dialogowego stworzyłem ten problem edittext.

Jeśli zapiszę Ciągi z edittext i przypiszę je ponownie w zmianie onCofiguration nadal wydają się domyślne wartość początkowa nie to, co zostało wprowadzone przed obrotem. Nawet jeśli wymuszę unieważnienie, wydaje się je aktualizować.

Naprawdę muszę rozwiązać problem z dialogiem lub problemem edittext.

Dzięki za pomoc.

Author: draksia, 2011-09-26

11 answers

Najlepszym sposobem uniknięcia tego problemu w dzisiejszych czasach jest użycie DialogFragment.

Utwórz nową klasę, która rozszerza DialogFragment. Override onCreateDialog i zwróć swoje stare Dialog lub AlertDialog.

Następnie można pokazać go z DialogFragment.show(fragmentManager, tag).

Oto przykład z Listener:

public class MyDialogFragment extends DialogFragment {

    public interface YesNoListener {
        void onYes();

        void onNo();
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        if (!(activity instanceof YesNoListener)) {
            throw new ClassCastException(activity.toString() + " must implement YesNoListener");
        }
    }

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        return new AlertDialog.Builder(getActivity())
                .setTitle(R.string.dialog_my_title)
                .setMessage(R.string.dialog_my_message)
                .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {

                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        ((YesNoListener) getActivity()).onYes();
                    }
                })
                .setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {

                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        ((YesNoListener) getActivity()).onNo();
                    }
                })
                .create();
    }
}

I w aktywności, którą wywołujesz:

new MyDialogFragment().show(getSupportFragmentManager(), "tag"); // or getFragmentManager() in API 11+

Ta odpowiedź pomaga wyjaśnić te trzy pozostałe pytania (i ich odpowiedzi):

 118
Author: Brais Gabin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-25 14:04:25
// Prevent dialog dismiss when orientation changes
private static void doKeepDialog(Dialog dialog){
    WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
    lp.copyFrom(dialog.getWindow().getAttributes());
    lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
    lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
    dialog.getWindow().setAttributes(lp);
}
public static void doLogout(final Context context){     
        final AlertDialog dialog = new AlertDialog.Builder(context)
        .setIcon(android.R.drawable.ic_dialog_alert)
        .setTitle(R.string.titlelogout)
        .setMessage(R.string.logoutconfirm)
        .setPositiveButton("Yes", new DialogInterface.OnClickListener()
        {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                ...   
            }

        })
        .setNegativeButton("No", null)      
        .show();    

        doKeepDialog(dialog);
    }
 41
Author: Chung IW,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-29 23:57:33

Jeśli zmieniasz układ przy zmianie orientacji, nie umieszczałbym android:configChanges="orientation" w manifeście, ponieważ i tak odtwarzasz widoki.

Zapisz aktualny stan Twojej aktywności (np. wprowadzony tekst, wyświetlone okno dialogowe, wyświetlone dane itp.) stosując te metody:

@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
}

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
    super.onRestoreInstanceState(savedInstanceState);
}

W ten sposób czynność przechodzi onCreate ponownie, a następnie wywołuje metodę onRestoreInstanceState, w której można ponownie ustawić wartość EditText.

Jeśli chcesz przechowywać bardziej złożone obiekty możesz użycie

@Override
public Object onRetainNonConfigurationInstance() {
}

Tutaj można zapisać dowolny obiekt i w onCreate wystarczy wywołać getLastNonConfigurationInstance();, aby uzyskać obiekt.

 5
Author: Maria Neumayer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-09-26 16:53:13

Wystarczy dodać android: configChanges= "orientacja" do swojej aktywności element w AndroidManifest.xml

Przykład:

<activity
            android:name=".YourActivity"
            android:configChanges="orientation"
            android:label="@string/app_name"></activity>
 2
Author: SAAM,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-27 05:43:11

Na to pytanie udzielono odpowiedzi dawno temu.

Jednak jest to non-hacky iproste rozwiązanie używam dla siebie.

Zrobiłem tę klasę pomocniczą dla siebie, więc możesz użyć jej również w swojej aplikacji.

Użycie to:

PersistentDialogFragment.newInstance(
        getBaseContext(),
        RC_REQUEST_CODE,
        R.string.message_text,
        R.string.positive_btn_text,
        R.string.negative_btn_text)
        .show(getSupportFragmentManager(), PersistentDialogFragment.TAG);

Lub

 PersistentDialogFragment.newInstance(
        getBaseContext(),
        RC_EXPLAIN_LOCATION,
        "Dialog title", 
        "Dialog Message", 
        "Positive Button", 
        "Negative Button", 
        false)
    .show(getSupportFragmentManager(), PersistentDialogFragment.TAG);





public class ExampleActivity extends Activity implements PersistentDialogListener{

        @Override
        void onDialogPositiveClicked(int requestCode) {
                switch(requestCode) {
                  case RC_REQUEST_CODE:
                  break;
                }
        }

        @Override
        void onDialogNegativeClicked(int requestCode) {
                switch(requestCode) {
                  case RC_REQUEST_CODE:
                  break;
                }          
        }
}
 2
Author: Ioane Sharvadze,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-19 15:05:37

Bardzo łatwym podejściem jest tworzenie okien dialogowych z metody onCreateDialog() (patrz uwaga poniżej). Pokazujesz je przez showDialog(). W ten sposób Android obsługuje obrót za Ciebie i nie musisz wywoływać dismiss() w onPause(), aby uniknąć okienka, a następnie nie musisz przywracać okna dialogowego. Z docs:

Pokaż okno dialogowe zarządzane przez to działanie. Wywołanie onCreateDialog (int, Bundle) zostanie wykonane z tym samym identyfikatorem przy pierwszym wywołaniu dla danego identyfikatora. Od tego czasu okno dialogowe zostanie automatycznie zapisane i przywrócone.

Zobacz Android docs showDialog () Aby uzyskać więcej informacji. Mam nadzieję, że to komuś pomoże!

Uwaga: W przypadku stosowania AlertDialog.Builder, nie wywołaj show() z onCreateDialog(), zamiast tego wywołaj create(). Jeżeli korzystasz z ProgressDialog, po prostu utwórz obiekt, Ustaw potrzebne parametry i zwróć go. Podsumowując, show() wewnątrz onCreateDialog() powoduje problemy, wystarczy utworzyć instancję de Dialog i zwrócić ją. To powinno zadziałać! (Mam problemy z używaniem showDialog () z onCreate () - właściwie nie pokazuje okna dialogowego-, ale jeśli używasz go w onresume () lub w wywołaniu zwrotnym listenera, działa dobrze).

 1
Author: Caumons,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-02-23 10:23:53

Możesz połączyć metody onSave/onRestore w oknie dialogowym z metodami Onsave/onRestore w oknie dialogowym , aby zachować stan okna dialogowego.

Uwaga: ta metoda działa dla tych "prostych" okien dialogowych, takich jak wyświetlanie komunikatu alertu. Nie odtwarza zawartości widoku sieci Web osadzonego w oknie dialogowym. Jeśli naprawdę chcesz zapobiec zwolnieniu złożonego okna dialogowego podczas rotacji, wypróbuj metodę Chung IW.

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
     super.onRestoreInstanceState(savedInstanceState);
     myDialog.onRestoreInstanceState(savedInstanceState.getBundle("DIALOG"));
     // Put your codes to retrieve the EditText contents and 
     // assign them to the EditText here.
}

@Override
protected void onSaveInstanceState(Bundle outState) {
     super.onSaveInstanceState(outState);
     // Put your codes to save the EditText contents and put them 
     // to the outState Bundle here.
     outState.putBundle("DIALOG", myDialog.onSaveInstanceState());
}
 1
Author: hackjutsu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-02 05:10:46

Wydaje się, że jest to nadal problem, nawet gdy "robi wszystko dobrze" i używa DialogFragment itp.

Istnieje wątek na Google Issue Tracker , który twierdzi, że jest to spowodowane starym odrzuceniem wiadomości pozostawionej w kolejce wiadomości. Dostarczone obejście jest dość proste:

    @Override
    public void onDestroyView() {
        /* Bugfix: https://issuetracker.google.com/issues/36929400 */
        if (getDialog() != null && getRetainInstance())
            getDialog().setDismissMessage(null);

        super.onDestroyView();
    }

Niesamowite, że jest to nadal potrzebne 7 lat po tym problem został po raz pierwszy zgłoszony.

 1
Author: BadCash,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-26 09:44:52

Zdecydowanie najlepszym podejściem jest użycie DialogFragment.

Oto moje rozwiązanie klasy wrapper, która pomaga zapobiec odrzuceniu różnych okien dialogowych w obrębie jednego fragmentu (lub aktywności z małą refaktoryzacją). Pomaga to również uniknąć ogromnej refaktoryzacji kodu, jeśli z pewnych powodów jest wiele AlertDialogs rozrzuconych między kodem z niewielkimi różnicami między nimi pod względem działań, wyglądu lub czegoś innego.

public class DialogWrapper extends DialogFragment {
    private static final String ARG_DIALOG_ID = "ARG_DIALOG_ID";

    private int mDialogId;

    /**
     * Display dialog fragment.
     * @param invoker  The fragment which will serve as {@link AlertDialog} alert dialog provider
     * @param dialogId The ID of dialog that should be shown
     */
    public static <T extends Fragment & DialogProvider> void show(T invoker, int dialogId) {
        Bundle args = new Bundle();
        args.putInt(ARG_DIALOG_ID, dialogId);
        DialogWrapper dialogWrapper = new DialogWrapper();
        dialogWrapper.setArguments(args);
        dialogWrapper.setTargetFragment(invoker, 0);
        dialogWrapper.show(invoker.getActivity().getSupportFragmentManager(), null);
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mDialogId = getArguments().getInt(ARG_DIALOG_ID);
    }

    @NonNull
    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        return getDialogProvider().getDialog(mDialogId);
    }

    private DialogProvider getDialogProvider() {
        return (DialogProvider) getTargetFragment();
    }

    public interface DialogProvider {
        Dialog getDialog(int dialogId);
    }
}

Jeśli chodzi o aktywność możesz wywołanie getContext() wewnątrz onCreateDialog(), wrzucenie go do interfejsu DialogProvider i zażądanie określonego okna dialogowego przez mDialogId. Cała logika postępowania z docelowym fragmentem powinna zostać usunięta.

Użycie z fragmentu:

public class MainFragment extends Fragment implements DialogWrapper.DialogProvider {
    private static final int ID_CONFIRMATION_DIALOG = 0;

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        Button btnHello = (Button) view.findViewById(R.id.btnConfirm);
        btnHello.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                DialogWrapper.show(MainFragment.this, ID_CONFIRMATION_DIALOG);
            }
        });
    }

    @Override
    public Dialog getDialog(int dialogId) {
        switch (dialogId) {
            case ID_CONFIRMATION_DIALOG:
                return createConfirmationDialog(); //Your AlertDialog
            default:
                throw new IllegalArgumentException("Unknown dialog id: " + dialogId);
        }
    }
}

Możesz przeczytać cały artykuł na moim blogu Jak zapobiec odrzuceniu okna dialogowego? i pobaw się kodem źródłowym.

 0
Author: Dmitry Korobeinikov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-13 17:07:40

Miałem podobny problem: po zmianie orientacji ekranu wywołano listen onDismiss okna dialogowego, mimo że użytkownik nie zamknął okna. Udało mi się obejść to, używając zamiast tego słuchacza onCancel, który wyzwalał się zarówno po naciśnięciu przycisku wstecz, jak i po dotknięciu poza dialogiem.

 0
Author: Sam,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-30 08:28:02

Po prostu użyj

ConfigurationChanges = Android.Content.PM.ConfigChanges.Orientation | Android.Content.PM.ConfigChanges.ScreenSize

I aplikacja będzie wiedzieć, jak obsługiwać obrót i rozmiar ekranu.

 -1
Author: user3384694,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-02 17:26:47