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.
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):
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);
}
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.
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>
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;
}
}
}
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).
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());
}
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.
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.
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.
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.
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