Merge "Fix bugs around inflated child fragments Framework edition"
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index 8124232..10ab2bc 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -414,6 +414,10 @@
// True if this fragment has been restored from previously saved state.
boolean mRestored;
+ // True if performCreateView has been called and a matching call to performDestroyView
+ // has not yet happened.
+ boolean mPerformedCreateView;
+
// Number of active back stack entries this fragment is in.
int mBackStackNesting;
@@ -611,7 +615,7 @@
Fragment f = (Fragment)clazz.newInstance();
if (args != null) {
args.setClassLoader(f.getClass().getClassLoader());
- f.mArguments = args;
+ f.setArguments(args);
}
return f;
} catch (ClassNotFoundException e) {
@@ -2464,6 +2468,7 @@
if (mChildFragmentManager != null) {
mChildFragmentManager.noteStateNotSaved();
}
+ mPerformedCreateView = true;
return onCreateView(inflater, container, savedInstanceState);
}
@@ -2690,6 +2695,7 @@
if (mLoaderManager != null) {
mLoaderManager.doReportNextStart();
}
+ mPerformedCreateView = false;
}
void performDestroy() {
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 07ef136..c7d6a48 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -1072,7 +1072,7 @@
if (f.mDeferStart && f.mState < Fragment.STARTED && newState > Fragment.STOPPED) {
newState = Fragment.STOPPED;
}
- if (f.mState < newState) {
+ if (f.mState <= newState) {
// For fragments that are created from a layout, when restoring from
// state we don't want to allow them to be created until they are
// being reloaded from the layout.
@@ -1089,65 +1089,59 @@
}
switch (f.mState) {
case Fragment.INITIALIZING:
- if (DEBUG) Log.v(TAG, "moveto CREATED: " + f);
- if (f.mSavedFragmentState != null) {
- f.mSavedViewState = f.mSavedFragmentState.getSparseParcelableArray(
- FragmentManagerImpl.VIEW_STATE_TAG);
- f.mTarget = getFragment(f.mSavedFragmentState,
- FragmentManagerImpl.TARGET_STATE_TAG);
- if (f.mTarget != null) {
- f.mTargetRequestCode = f.mSavedFragmentState.getInt(
- FragmentManagerImpl.TARGET_REQUEST_CODE_STATE_TAG, 0);
- }
- f.mUserVisibleHint = f.mSavedFragmentState.getBoolean(
- FragmentManagerImpl.USER_VISIBLE_HINT_TAG, true);
- if (!f.mUserVisibleHint) {
- f.mDeferStart = true;
- if (newState > Fragment.STOPPED) {
- newState = Fragment.STOPPED;
+ if (newState > Fragment.INITIALIZING) {
+ if (DEBUG) Log.v(TAG, "moveto CREATED: " + f);
+ if (f.mSavedFragmentState != null) {
+ f.mSavedViewState = f.mSavedFragmentState.getSparseParcelableArray(
+ FragmentManagerImpl.VIEW_STATE_TAG);
+ f.mTarget = getFragment(f.mSavedFragmentState,
+ FragmentManagerImpl.TARGET_STATE_TAG);
+ if (f.mTarget != null) {
+ f.mTargetRequestCode = f.mSavedFragmentState.getInt(
+ FragmentManagerImpl.TARGET_REQUEST_CODE_STATE_TAG, 0);
+ }
+ f.mUserVisibleHint = f.mSavedFragmentState.getBoolean(
+ FragmentManagerImpl.USER_VISIBLE_HINT_TAG, true);
+ if (!f.mUserVisibleHint) {
+ f.mDeferStart = true;
+ if (newState > Fragment.STOPPED) {
+ newState = Fragment.STOPPED;
+ }
}
}
- }
- f.mHost = mHost;
- f.mParentFragment = mParent;
- f.mFragmentManager = mParent != null
- ? mParent.mChildFragmentManager : mHost.getFragmentManagerImpl();
- dispatchOnFragmentPreAttached(f, mHost.getContext(), false);
- f.mCalled = false;
- f.onAttach(mHost.getContext());
- if (!f.mCalled) {
- throw new SuperNotCalledException("Fragment " + f
- + " did not call through to super.onAttach()");
- }
- if (f.mParentFragment == null) {
- mHost.onAttachFragment(f);
- } else {
- f.mParentFragment.onAttachFragment(f);
- }
- dispatchOnFragmentAttached(f, mHost.getContext(), false);
-
- if (!f.mRetaining) {
- f.performCreate(f.mSavedFragmentState);
- dispatchOnFragmentCreated(f, f.mSavedFragmentState, false);
- } else {
- f.restoreChildFragmentState(f.mSavedFragmentState, true);
- f.mState = Fragment.CREATED;
- }
- f.mRetaining = false;
- if (f.mFromLayout) {
- // For fragments that are part of the content view
- // layout, we need to instantiate the view immediately
- // and the inflater will take care of adding it.
- f.mView = f.performCreateView(f.getLayoutInflater(
- f.mSavedFragmentState), null, f.mSavedFragmentState);
- if (f.mView != null) {
- f.mView.setSaveFromParentEnabled(false);
- if (f.mHidden) f.mView.setVisibility(View.GONE);
- f.onViewCreated(f.mView, f.mSavedFragmentState);
- dispatchOnFragmentViewCreated(f, f.mView, f.mSavedFragmentState, false);
+ f.mHost = mHost;
+ f.mParentFragment = mParent;
+ f.mFragmentManager = mParent != null
+ ? mParent.mChildFragmentManager : mHost.getFragmentManagerImpl();
+ dispatchOnFragmentPreAttached(f, mHost.getContext(), false);
+ f.mCalled = false;
+ f.onAttach(mHost.getContext());
+ if (!f.mCalled) {
+ throw new SuperNotCalledException("Fragment " + f
+ + " did not call through to super.onAttach()");
}
+ if (f.mParentFragment == null) {
+ mHost.onAttachFragment(f);
+ } else {
+ f.mParentFragment.onAttachFragment(f);
+ }
+ dispatchOnFragmentAttached(f, mHost.getContext(), false);
+
+ if (!f.mRetaining) {
+ f.performCreate(f.mSavedFragmentState);
+ dispatchOnFragmentCreated(f, f.mSavedFragmentState, false);
+ } else {
+ f.restoreChildFragmentState(f.mSavedFragmentState, true);
+ f.mState = Fragment.CREATED;
+ }
+ f.mRetaining = false;
}
case Fragment.CREATED:
+ // This is outside the if statement below on purpose; we want this to run
+ // even if we do a moveToState from CREATED => *, CREATED => CREATED, and
+ // * => CREATED as part of the case fallthrough above.
+ ensureInflatedFragmentView(f);
+
if (newState > Fragment.CREATED) {
if (DEBUG) Log.v(TAG, "moveto ACTIVITY_CREATED: " + f);
if (!f.mFromLayout) {
@@ -1281,6 +1275,7 @@
}
f.mContainer = null;
f.mView = null;
+ f.mInLayout = false;
}
case Fragment.CREATED:
if (newState < Fragment.CREATED) {
@@ -1340,6 +1335,19 @@
moveToState(f, mCurState, 0, 0, false);
}
+ void ensureInflatedFragmentView(Fragment f) {
+ if (f.mFromLayout && !f.mPerformedCreateView) {
+ f.mView = f.performCreateView(f.getLayoutInflater(
+ f.mSavedFragmentState), null, f.mSavedFragmentState);
+ if (f.mView != null) {
+ f.mView.setSaveFromParentEnabled(false);
+ if (f.mHidden) f.mView.setVisibility(View.GONE);
+ f.onViewCreated(f.mView, f.mSavedFragmentState);
+ dispatchOnFragmentViewCreated(f, f.mView, f.mSavedFragmentState, false);
+ }
+ }
+ }
+
/**
* Fragments that have been shown or hidden don't have their visibility changed or
* animations run during the {@link #showFragment(Fragment)} or {@link #hideFragment(Fragment)}
@@ -3262,7 +3270,9 @@
}
// If we haven't finished entering the CREATED state ourselves yet,
- // push the inflated child fragment along.
+ // push the inflated child fragment along. This will ensureInflatedFragmentView
+ // at the right phase of the lifecycle so that we will have mView populated
+ // for compliant fragments below.
if (mCurState < Fragment.CREATED && fragment.mFromLayout) {
moveToState(fragment, Fragment.CREATED, 0, 0, false);
} else {