Quantcast
Channel: Android Magic » Library
Viewing all articles
Browse latest Browse all 5

Why Android DialogFragment confuses me – part 2

$
0
0

In Part 1 I lost my DialogFragment after a device rotation, having set the public void setRetainInstance(true). Turns out there is a bug in the DialogFragment class, where when the view is destroyed, the dismiss() and dismissInternal() methods are called and the fragment gets removed. This can be prevented with a “dirty” trick.

@Override
public void onDestroyView() {
  if (getDialog() != null && getRetainInstance())
    getDialog().setOnDismissListener(null);
  super.onDestroyView();
}

Another famous “bug” happens when you want to show a DialogFragment in protected void onActivityResult(int requestCode, int resultCode, Intent data) or protected void onPostExecute(Result result) or public abstract void onLoadFinished(Loader loader, D data). Trying to do that will result in a java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState.

Let’s look inside the FragmentManager.java class, to see where that exception is thrown.

private void checkStateLoss() {
        if (mStateSaved) {
            throw new IllegalStateException(
                    "Can not perform this action after onSaveInstanceState");
        }
        if (mNoTransactionsBecause != null) {
            throw new IllegalStateException(
                    "Can not perform this action inside of " + mNoTransactionsBecause);
        }
    }

When state of the Activity is saved in the protected void onSaveInstanceState(Bundle outState),  the FragmentManager#saveAllState() internal method also gets called, setting the mStateSaved to true.

protected void onSaveInstanceState(Bundle outState) {
        outState.putBundle(WINDOW_HIERARCHY_TAG, mWindow.saveHierarchyState());
        Parcelable p = mFragments.saveAllState();
        if (p != null) {
            outState.putParcelable(FRAGMENTS_TAG, p);
        }
        getApplication().dispatchActivitySaveInstanceState(this, outState);
}

This means that by default no fragment transaction is allowed once the onSaveInstanceState(Bundle outState()) has been called.

Once the Activity state has been saved with onSaveInstanceState(Bundle outState), it can be killed anytime. A background operation started inside that activity is asynchronous, so there is no guarantee that when it terminates, the activity will still be there waiting for the dialog to show up Same with the onActivityResult callback.

I could push my luck and use commitAllowingStateLoss() but it is not recommended and there is a better way to do it (hint: onPostResume or onResumeFragments()).

There is another blog post on the subject of Fragment Transactions & Activity State Loss written by Alex Lockwood so I really recommend you to read it, it provides useful insight into this problem.

Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live.

The post Why Android DialogFragment confuses me – part 2 appeared first on Android Magic.


Viewing all articles
Browse latest Browse all 5

Latest Images

Trending Articles



Latest Images