Prevent dialog dismissal on screen rotation in Android
Solution 1
The best way to avoid this problem nowadays is by using a DialogFragment
.
Create a new class which extends DialogFragment
. Override onCreateDialog
and return your old Dialog
or an AlertDialog
.
Then you can show it with DialogFragment.show(fragmentManager, tag)
.
Here's an example with a 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();
}
}
And in the Activity you call:
new MyDialogFragment().show(getSupportFragmentManager(), "tag"); // or getFragmentManager() in API 11+
This answer helps explain these other three questions (and their answers):
- Android Best way of avoid Dialogs to dismiss after a device rotation
- Android DialogFragment vs Dialog
- How can I show a DialogFragment using compatibility package?
Solution 2
// 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);
}
Solution 3
If you're changing the layout on orientation change I wouldn't put android:configChanges="orientation"
in your manifest because you're recreating the views anyway.
Save the current state of your activity (like text entered, shown dialog, data displayed etc.) using these methods:
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
}
That way the activity goes through onCreate again and afterwards calls the onRestoreInstanceState method where you can set your EditText value again.
If you want to store more complex Objects you can use
@Override
public Object onRetainNonConfigurationInstance() {
}
Here you can store any object and in onCreate you just have to call getLastNonConfigurationInstance();
to get the Object.
Solution 4
Just add android:configChanges="orientation" with your activity element in AndroidManifest.xml
Example:
<activity
android:name=".YourActivity"
android:configChanges="orientation"
android:label="@string/app_name"></activity>
Solution 5
This question was answered a long time ago.
Yet this is non-hacky and simple solution I use for myself.
I did this helper class for myself, so you can use it in your application too.
Usage is:
PersistentDialogFragment.newInstance(
getBaseContext(),
RC_REQUEST_CODE,
R.string.message_text,
R.string.positive_btn_text,
R.string.negative_btn_text)
.show(getSupportFragmentManager(), PersistentDialogFragment.TAG);
Or
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;
}
}
}
draksia
Updated on July 08, 2022Comments
-
draksia almost 2 years
I am trying to prevent dialogs built with Alert builder from being dismissed when the Activity is restarted.
If I overload the onConfigurationChanged method I can successfully do this and reset the layout to correct orientation but I lose sticky text feature of edittext. So in solving the dialog problem I have created this edittext problem.
If I save the strings from the edittext and reassign them in the onCofiguration change they still seem to default to initial value not what was entered before rotation. Even if I force an invalidate does seem to update them.
I really need to solve either the dialog problem or the edittext problem.
Thanks for the help.
-
Caumons about 12 yearsFor which case would you need some code? The onCreateDialog() or showing it with the builder and calling show() to it?
-
neteinstein about 12 yearsI have managed to do it.. but the thing is, onCreateDialog() is now deprecated :-\
-
Caumons about 12 yearsOK! Have in mind that most of Android devices still work with 2.X versions, so you can use it anyway! Have a look at Android platform versions usage
-
neteinstein about 12 yearsStill, what's the other option if not onCreateDialog?
-
Caumons about 12 yearsYou can use the builder classes e.g.
AlertDialog.Builder
. If you use it insideonCreateDialog()
, instead of usingshow()
return the result ofcreate()
. Else, callshow()
and store the returned AlertDialog into an attribute of the Activity and inonPause()
dismiss()
it if showing in order to avoid a WindowLeak. Hope it helps! -
ForceMagic about 10 years
OnRetainNonConfigurationInstance()
is now deprecated as the Doc says : developer.android.com/reference/android/app/…setRetainInstance(boolean retain)
should be use instead : developer.android.com/reference/android/app/… -
Chung IW over 9 yearsTo whom find my code not useful, try it before click :-)
-
nmvictor almost 9 yearsWorks, don't know how but it works! Clean simple and abstract solution, thanks.
-
Adrian Olar over 8 yearsAmazing solution, very simple unlike the other solutions I found, thank you so much, you helped me prevent my app from crashing and solved a crucial bug!!!
-
Zuko over 8 yearsCool stuff @ChungIW Now thats coding I adhore
-
Sharp Edge over 8 yearsThis used to work well, now on lollipop it doesn't work on some devices, dialog still disappears (sigh)
-
Alpha Huang about 8 yearsThere is a button in my app to call .show(), I have to remember the state of the alert dialog, showing/dismissed. Is there a way to keep the dialog without calling .show()?
-
Stephan Henningsen over 7 years@ChungIW, Could you please elaborate? Why do Dialogs usually not survive an orientation change and why does this fix it?
-
farahm over 7 yearsIt says that
onAttach
is deprecated now. What should be done instead? -
Stan Mots over 7 years@faraz_ahmed_kamran, you should use
onAttach(Context context)
andandroid.support.v4.app.DialogFragment
. TheonAttach
method takescontext
instead ofactivity
as a parameter now. -
Peter Chaula over 7 years@StephanHenningsen the
Activity
gets destroyed on orientation change. -
Stephan Henningsen over 7 years@ChungIW The orientation changes - the Activity gets destroyed - the Activity gets recreated - And your code ensure the Dialog gets recreated. How? Why does it work?
-
Miha_x64 about 7 years@ForceMagic
setRetainInstance
is completely different: it's for Fragments and it does not guarantee you that instance will be retained. -
The incredible Jan about 7 yearsI think this code is bad. doLogout() has a reference to context which is/contains the activity. The activity cannot be destroyed which can cause a memory leak. I was looking for a possibility to use AlertDialog from static context but now I'm sure that it is impossible. The result can only be garbage I think.
-
Udo Klimaschewski over 6 yearsIt just looks like it works. The dialog stays open, but it has no connection to the newly created activity or fragment (it gets newly created on each orientation change). So you can't do anything that requires a
Context
inside the dialog buttonsOnClickListener
. -
Sam over 6 yearsThis can cause the dialog to display incorrectly in some circumstances.
-
Hexise about 6 yearsThis code works but not recommend at all. It leaks activity reference, which is why the dialog can persistent. This is a very bad practice which will lead to memory leak.
-
tsig almost 6 yearsandroid:configChanges="orientation|screenSize" Note: If your application targets Android 3.2 (API level 13) or higher, then you should also declare the "screenSize" configuration, because it also changes when a device switches between portrait and landscape orientations.
-
Mygod over 5 yearsThere's probably no need for
YesNoListener
though. See this answer. -
Roshana Pitigala about 5 yearsWhile this may answer the question it's better to add some description on how this answer may help to solve the issue. Please read How do I write a good answer to know more.
-
CoolMind about 4 yearsSee also stackoverflow.com/questions/14657490/….
-
Luis A. Florit over 2 yearsDidn't work for me on Android 11.