Hi I am developing an app that uses maps.
I am using Fragment Activity and a fragment named Fragment-A.
In Fragment-A there is a button, on clicking that button a Dialog Fragment pops up, displays a map with some location received previously from server.
Let us say this dialog fragment is DialogFragment-B.
It has a button to close, a button to navigate to google maps app to get directions.
If user navigate to DialogFragment-B and returns back to the Fragment-A, by clicking close button every thing is working fine.
But if the user clicks on back button the existing dialog fragment will close normally and the app functions normally.
But if the user then pressed home button or received a phone call and onResume is called even though the DialogFragment-B is dismissed earlier, it reappears and pressing close crashes the app with a null pointer exception
Here is my code to open the DialogFragment-B.
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
android.app.Fragment prev = fm.findFragmentByTag(MY_MAP);
if (prev != null) {
ft.remove(prev);
}
MyMapFragmentDialog newFragment = MyMapFragmentDialog
.newInstance(eachPost);
newFragment.show(ft, MY_MAP);
In DialogFragment-B on clicking close button, I call MyMapFragmentDialog.this.dismiss();
Please if any one have encountered this issue and overcame, guide me through.
I had the same issue and it was solved by making sure I call super.onDismiss(dialog)
in the onDismiss
method of my DialogFragment
subclass.
Update: The answer by Kalina is a more elegant and simple solution - as I figured out later!
I am facing the same issue in one of my apps, and not finding the answer anywhere, went through the source code of the DialogFragment class, which is available at:
http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.0.1_r1/android/app/DialogFragment.java#DialogFragment.onDismiss%28android.content.DialogInterface%29
and there, I found the probable reason written in a comment, within the source of onDismiss(DialogInterface dialog) method:
// Note: we need to use allowStateLoss, because the dialog
// dispatches this asynchronously so we can receive the call
// after the activity is paused. Worst case, when the user comes
// back to the activity they see the dialog again.
What I understood from this is that dismissal is not saved to the instance state, and when the activity resumes, it promptly shows it again as part of the instance state restoration - assuming that the fragment was never dismissed. Being an asynchronous event, there is no safe way to commit the dismiss without risking a
java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
exception and consequent crash, which is probably why the authors of the class chose to do it this way.
The solution that worked for me was to separately monitor the state of the DialogFragment, by:
-
@Override
public void onDismiss(DialogInterface dialog) {
// dialogDismissed is a Class level variable in the containing Activity,
// must be set to false each time the DialogFragment is shown
dialogDismissed = true;
}
Note: if the DialogFragment is a separate Class, then then a method in the Activity will need to be called from the onDismiss to do this, perhaps by setting up an Interface
This flag must then be checked in the activity onResume() and a dismiss forced (after checking that the dialog is not null):
-
@Override
public void onResume() {
super.onResume();
//...
if (dialogDismissed && dialog != null) {
dialog.dismiss();
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With