A similar question has been asked before, but my case is different.
I have DialogFragments all over my app. When I rotate the phone, all of the DialogFragments come back without issue except this one.
I've littered the life cycle callbacks with Log messages to see what is going on, and this is the scenario:
- My DialogFragment is created and shown
- On rotation, I save whatever I want to into a bundle for restoration afterwards.
- DialogFragment is successfully recreated. I know because onCreate through to onResume are called.
- Immediately after resumption, for some inexplicable reason, onPause, onStop, onDestroyView, onDestroy and onDetach are called in rapid succession. The DialogFragment is destroyed immediately after recreation and I don't know why.
Any help is much appreciated. The DialogFragment starts an activity for result to take a picture. It works well for most phones, but the Galaxy S3 camera causes orientation changes that force the activity to be recreated. I don't mind this, I know how to handle activity recreation, but this I've never encountered.
The DialogFragment is started via a RecyclerView adapter callback from a regular fragment, in the main hosting activity.
I do not show the DialogFragment using the ChildFragmentManger in the fragment hosting the RecyclerView because multiple fragments can show this DialogFragment and the function is always the same. It was much more prudent to have the activity receive the callback regardless of which fragment started it.
From the fragment:
selectionPickAdapter.setAdapterListener(new selectionPickAdapter.AdapterListener() {
@Override
public void onSelectionClicked(Selection selection) {
if (getActivity() instanceof RankingActivity) {
((RankingActivity) getActivity()).onSelectionClicked(selection);
}
}
});
The main hosting activity receives the call back and shows it thus:
@Override
public void onSelectionClicked(Selection selection) {
if (isSignedInUser) {
selectionsToEdit.put(selection.hashCode(), selection);
if (baseCategory != null) {
selection.setCategory(baseCategory);
}
RankingSelectionEditDialogFragment rankingSelectionEditDialogFragment =
RankingSelectionEditDialogFragment.newInstance(SELECTION_EDIT, selection.hashCode(), selection);
rankingSelectionEditDialogFragment.show(getSupportFragmentManager(), EDIT_TAG);
}
else {
Intent i = new Intent(this, BusinessActivity.class);
i.putExtra(Constants.BUSINESS, selection.getBusiness().getId());
startActivity(i);
}
}
These are my lifecycle callbacks:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
selectionToEdit = savedInstanceState.getParcelable(SELECTION_TO_EDIT);
imagePath = savedInstanceState.getString(IMAGE_PATH);
}
else {
selectionToEdit = getArguments().getParcelable(SELECTION_TO_EDIT);
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
if (savedInstanceState != null) {
Log.i(TAG, "CREATED A SECOND TIME!");
}
else {
Log.i(TAG, "CREATED ONCE!");
}
// Inflate the layout for this fragment
View rootView = inflater.inflate(R.layout.fragment_ranking_edit, container, false);
initializeViewComponents(rootView);
return rootView;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setupFragment(selectionToEdit);
}
@Override
public void onResume() {
super.onResume();
Log.i(TAG, "onResume");
Dialog dialog = getDialog();
if (dialog != null) { // Only do this if returning a dialog, not a fragment
Log.i(TAG, "Dialog is not null");
SharedPreferences sharedPreferences
= getActivity().getSharedPreferences(Constants.PREFS, Context.MODE_PRIVATE);
// Get items required to put dialog just under the ActionBar.
int screenWidth = sharedPreferences.getInt(Constants.SCREEN_WIDTH, 720);
int screenHeight = sharedPreferences.getInt(Constants.SCREEN_HEIGHT, 1280);
int screenDPI = sharedPreferences.getInt(Constants.SCREEN_DPI, 320);
Window window = dialog.getWindow();
window.setLayout(screenWidth, WindowManager.LayoutParams.WRAP_CONTENT);
WindowManager.LayoutParams windowLayoutParams = window.getAttributes();
window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
windowLayoutParams.y = -((screenHeight / 2) - 56) * (screenDPI / 160);
window.setAttributes(windowLayoutParams);
if (dialog.isShowing()) {
Log.i(TAG, "Dialog is showing");
}
else {
Log.i(TAG, "Dialog is not showing");
}
}
else {
Log.i(TAG, "Dialog is null");
}
Log.i(TAG, "onResume finished");
}
/**
* The system calls this only when creating the layout in a dialog.
*/
@Override
@NonNull
public Dialog onCreateDialog(Bundle savedInstanceState) {
Dialog dialog = super.onCreateDialog(savedInstanceState);
// The only reason you might override this method when using onCreateView() is
// to modify any dialog characteristics. For example, the dialog includes a
// title by default, but your custom layout might not need it. So here you can
// remove the dialog title, but you must call the superclass to get the Dialog.
SharedPreferences sharedPreferences
= getActivity().getSharedPreferences(Constants.PREFS, Context.MODE_PRIVATE);
// Get items required to put dialog just under the ActionBar.
int screenWidth = sharedPreferences.getInt(Constants.SCREEN_WIDTH, 720);
int screenHeight = sharedPreferences.getInt(Constants.SCREEN_HEIGHT, 1280);
int screenDPI = sharedPreferences.getInt(Constants.SCREEN_DPI, 320);
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
Window window = dialog.getWindow();
window.setLayout(screenWidth, WindowManager.LayoutParams.WRAP_CONTENT);
WindowManager.LayoutParams windowLayoutParams = window.getAttributes();
window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
windowLayoutParams.y = -((screenHeight / 2) - 56) * (screenDPI / 160);
windowLayoutParams.flags &= ~WindowManager.LayoutParams.FLAG_DIM_BEHIND;
window.setAttributes(windowLayoutParams);
return dialog;
}
/**
* Restore the previous currentFragment before the dialog was brought up
*/
@Override
public void dismiss() { // Used when the user deliberately dismisses the dialog
Log.i(TAG, "Dismissed");
super.dismiss(); // Ensure Super class method is called
}
/**
* Restore the previous currentFragment before the dialog was brought up
*/
@Override
public void onCancel(DialogInterface dialog) { // Used when the user inadvertently leaves the dialog,
// e.g back pressed or touched outside the dialog
Log.i(TAG, "Cancelled");
super.onCancel(dialog); // Ensure Super class method is called
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelable(SELECTION_TO_EDIT, selectionToEdit);
outState.putString(IMAGE_PATH, imagePath);
}
@Override
public void onPause() {
Log.i(TAG, "onPause");
super.onPause();
}
@Override
public void onStop() {
Log.i(TAG, "onStop");
super.onStop();
}
@Override
public void onDestroyView() {
Log.i(TAG, "View Destroyed");
super.onDestroyView();
}
@Override
public void onDestroy() {
Log.i(TAG, "onDestroy");
super.onDestroy();
}
@Override
public void onDetach() {
Log.i(TAG, "onDetach");
super.onDetach();
}
EDIT: I've fixed the issue. To show the DialogFragment, I should use the ChildFragmentManager of the hosting fragment and not the activity. That is, changing this:
RankingSelectionEditDialogFragment rankingSelectionEditDialogFragment =
RankingSelectionEditDialogFragment.newInstance(SELECTION_EDIT, selection.hashCode(), selection);
rankingSelectionEditDialogFragment.show(getSupportFragmentManager(), EDIT_TAG);
to this:
RankingSelectionEditDialogFragment rankingSelectionEditDialogFragment =
RankingSelectionEditDialogFragment.newInstance(SELECTION_EDIT, selection.hashCode(), selection);
switch (currentFragment) {
case CATEGORY_PICK:
rankingCategoryPickFragment = (RankingCategoryPickFragment)
getSupportFragmentManager().findFragmentByTag(CATEGORY_PICK_TAG);
if(rankingCategoryPickFragment != null) {
rankingSelectionEditDialogFragment.show
(rankingCategoryPickFragment.getChildFragmentManager(), EDIT_TAG);
}
break;
case BUSINESS_SORT:
rankingBusinessSortParentFragment = (RankingBusinessSortParentFragment)
getSupportFragmentManager().findFragmentByTag(BUSINESS_SORT_TAG);
if(rankingBusinessSortParentFragment != null) {
rankingSelectionEditDialogFragment.show
(rankingBusinessSortParentFragment.getChildFragmentManager(), EDIT_TAG);
}
break;
was the ticket. Hope that helps anybody else with a similar issue.