Skip to content

Commit ee76efb

Browse files
author
Dianne Hackborn
committed
Fix issue #6584942 IllegalStateException: Failure saving state...
...active SuggestFragment{419494f0} has cleared index: -1 There were issues when the same fragment was removed and then added again before completely finishing the remove (such as due to a running animation). Two fixes: - Now when you call FragmentTransaction.replace() and are replacing a fragment with the same fragment, this becomes a no-op, to avoid visual artifacts in the transition and bad states. - When we are moving the fragment state up and it is currently animating away to the INITIALIZED state, we could end up making the fragment inactive as part of the cleanup. In this case it shouldn't be made inactive; we just need to initialize it but keep it active since we are going to continue to use it. Bug: 6584942 Change-Id: I8bfd73f2d8ef8f67b541b3e2525dfa5db6c3bfa5
1 parent 51df04b commit ee76efb

File tree

3 files changed

+56
-38
lines changed

3 files changed

+56
-38
lines changed

core/java/android/app/BackStackRecord.java

Lines changed: 38 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ public BackStackState(FragmentManagerImpl fm, BackStackRecord bse) {
5353
int pos = 0;
5454
while (op != null) {
5555
mOps[pos++] = op.cmd;
56-
mOps[pos++] = op.fragment.mIndex;
56+
mOps[pos++] = op.fragment != null ? op.fragment.mIndex : -1;
5757
mOps[pos++] = op.enterAnim;
5858
mOps[pos++] = op.exitAnim;
5959
mOps[pos++] = op.popEnterAnim;
@@ -99,8 +99,13 @@ public BackStackRecord instantiate(FragmentManagerImpl fm) {
9999
op.cmd = mOps[pos++];
100100
if (FragmentManagerImpl.DEBUG) Log.v(FragmentManagerImpl.TAG,
101101
"BSE " + bse + " set base fragment #" + mOps[pos]);
102-
Fragment f = fm.mActive.get(mOps[pos++]);
103-
op.fragment = f;
102+
int findex = mOps[pos++];
103+
if (findex >= 0) {
104+
Fragment f = fm.mActive.get(findex);
105+
op.fragment = f;
106+
} else {
107+
op.fragment = null;
108+
}
104109
op.enterAnim = mOps[pos++];
105110
op.exitAnim = mOps[pos++];
106111
op.popEnterAnim = mOps[pos++];
@@ -506,9 +511,11 @@ void bumpBackStackNesting(int amt) {
506511
+ " by " + amt);
507512
Op op = mHead;
508513
while (op != null) {
509-
op.fragment.mBackStackNesting += amt;
510-
if (FragmentManagerImpl.DEBUG) Log.v(TAG, "Bump nesting of "
511-
+ op.fragment + " to " + op.fragment.mBackStackNesting);
514+
if (op.fragment != null) {
515+
op.fragment.mBackStackNesting += amt;
516+
if (FragmentManagerImpl.DEBUG) Log.v(TAG, "Bump nesting of "
517+
+ op.fragment + " to " + op.fragment.mBackStackNesting);
518+
}
512519
if (op.removed != null) {
513520
for (int i=op.removed.size()-1; i>=0; i--) {
514521
Fragment r = op.removed.get(i);
@@ -568,23 +575,29 @@ public void run() {
568575
Fragment old = mManager.mAdded.get(i);
569576
if (FragmentManagerImpl.DEBUG) Log.v(TAG,
570577
"OP_REPLACE: adding=" + f + " old=" + old);
571-
if (old.mContainerId == f.mContainerId) {
572-
if (op.removed == null) {
573-
op.removed = new ArrayList<Fragment>();
578+
if (f == null || old.mContainerId == f.mContainerId) {
579+
if (old == f) {
580+
op.fragment = f = null;
581+
} else {
582+
if (op.removed == null) {
583+
op.removed = new ArrayList<Fragment>();
584+
}
585+
op.removed.add(old);
586+
old.mNextAnim = op.exitAnim;
587+
if (mAddToBackStack) {
588+
old.mBackStackNesting += 1;
589+
if (FragmentManagerImpl.DEBUG) Log.v(TAG, "Bump nesting of "
590+
+ old + " to " + old.mBackStackNesting);
591+
}
592+
mManager.removeFragment(old, mTransition, mTransitionStyle);
574593
}
575-
op.removed.add(old);
576-
old.mNextAnim = op.exitAnim;
577-
if (mAddToBackStack) {
578-
old.mBackStackNesting += 1;
579-
if (FragmentManagerImpl.DEBUG) Log.v(TAG, "Bump nesting of "
580-
+ old + " to " + old.mBackStackNesting);
581-
}
582-
mManager.removeFragment(old, mTransition, mTransitionStyle);
583594
}
584595
}
585596
}
586-
f.mNextAnim = op.enterAnim;
587-
mManager.addFragment(f, false);
597+
if (f != null) {
598+
f.mNextAnim = op.enterAnim;
599+
mManager.addFragment(f, false);
600+
}
588601
} break;
589602
case OP_REMOVE: {
590603
Fragment f = op.fragment;
@@ -644,10 +657,12 @@ public void popFromBackStack(boolean doStateMove) {
644657
} break;
645658
case OP_REPLACE: {
646659
Fragment f = op.fragment;
647-
f.mNextAnim = op.popExitAnim;
648-
mManager.removeFragment(f,
649-
FragmentManagerImpl.reverseTransit(mTransition),
650-
mTransitionStyle);
660+
if (f != null) {
661+
f.mNextAnim = op.popExitAnim;
662+
mManager.removeFragment(f,
663+
FragmentManagerImpl.reverseTransit(mTransition),
664+
mTransitionStyle);
665+
}
651666
if (op.removed != null) {
652667
for (int i=0; i<op.removed.size(); i++) {
653668
Fragment old = op.removed.get(i);

core/java/android/app/Fragment.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1503,7 +1503,7 @@ public boolean onContextItemSelected(MenuItem item) {
15031503
public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
15041504
writer.print(prefix); writer.print("mFragmentId=#");
15051505
writer.print(Integer.toHexString(mFragmentId));
1506-
writer.print(" mContainerId#=");
1506+
writer.print(" mContainerId=#");
15071507
writer.print(Integer.toHexString(mContainerId));
15081508
writer.print(" mTag="); writer.println(mTag);
15091509
writer.print(prefix); writer.print("mState="); writer.print(mState);

core/java/android/app/FragmentManager.java

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -726,11 +726,12 @@ public void performPendingDeferredStart(Fragment f) {
726726
return;
727727
}
728728
f.mDeferStart = false;
729-
moveToState(f, mCurState, 0, 0);
729+
moveToState(f, mCurState, 0, 0, false);
730730
}
731731
}
732732

733-
void moveToState(Fragment f, int newState, int transit, int transitionStyle) {
733+
void moveToState(Fragment f, int newState, int transit, int transitionStyle,
734+
boolean keepActive) {
734735
// Fragments that are not currently added will sit in the onCreate() state.
735736
if (!f.mAdded && newState > Fragment.CREATED) {
736737
newState = Fragment.CREATED;
@@ -757,7 +758,7 @@ void moveToState(Fragment f, int newState, int transit, int transitionStyle) {
757758
// animation, move to whatever the final state should be once
758759
// the animation is done, and then we can proceed from there.
759760
f.mAnimatingAway = null;
760-
moveToState(f, f.mStateAfterAnimating, 0, 0);
761+
moveToState(f, f.mStateAfterAnimating, 0, 0, true);
761762
}
762763
switch (f.mState) {
763764
case Fragment.INITIALIZING:
@@ -940,7 +941,7 @@ public void onAnimationEnd(Animator anim) {
940941
if (fragment.mAnimatingAway != null) {
941942
fragment.mAnimatingAway = null;
942943
moveToState(fragment, fragment.mStateAfterAnimating,
943-
0, 0);
944+
0, 0, false);
944945
}
945946
}
946947
});
@@ -992,11 +993,13 @@ public void onAnimationEnd(Animator anim) {
992993
throw new SuperNotCalledException("Fragment " + f
993994
+ " did not call through to super.onDetach()");
994995
}
995-
if (!f.mRetaining) {
996-
makeInactive(f);
997-
} else {
998-
f.mActivity = null;
999-
f.mFragmentManager = null;
996+
if (!keepActive) {
997+
if (!f.mRetaining) {
998+
makeInactive(f);
999+
} else {
1000+
f.mActivity = null;
1001+
f.mFragmentManager = null;
1002+
}
10001003
}
10011004
}
10021005
}
@@ -1007,7 +1010,7 @@ public void onAnimationEnd(Animator anim) {
10071010
}
10081011

10091012
void moveToState(Fragment f) {
1010-
moveToState(f, mCurState, 0, 0);
1013+
moveToState(f, mCurState, 0, 0, false);
10111014
}
10121015

10131016
void moveToState(int newState, boolean always) {
@@ -1029,7 +1032,7 @@ void moveToState(int newState, int transit, int transitStyle, boolean always) {
10291032
for (int i=0; i<mActive.size(); i++) {
10301033
Fragment f = mActive.get(i);
10311034
if (f != null) {
1032-
moveToState(f, newState, transit, transitStyle);
1035+
moveToState(f, newState, transit, transitStyle, false);
10331036
if (f.mLoaderManager != null) {
10341037
loadersRunning |= f.mLoaderManager.hasRunningLoaders();
10351038
}
@@ -1122,7 +1125,7 @@ public void removeFragment(Fragment fragment, int transition, int transitionStyl
11221125
fragment.mAdded = false;
11231126
fragment.mRemoving = true;
11241127
moveToState(fragment, inactive ? Fragment.INITIALIZING : Fragment.CREATED,
1125-
transition, transitionStyle);
1128+
transition, transitionStyle, false);
11261129
}
11271130
}
11281131

@@ -1189,7 +1192,7 @@ public void detachFragment(Fragment fragment, int transition, int transitionStyl
11891192
mNeedMenuInvalidate = true;
11901193
}
11911194
fragment.mAdded = false;
1192-
moveToState(fragment, Fragment.CREATED, transition, transitionStyle);
1195+
moveToState(fragment, Fragment.CREATED, transition, transitionStyle, false);
11931196
}
11941197
}
11951198
}
@@ -1204,7 +1207,7 @@ public void attachFragment(Fragment fragment, int transition, int transitionStyl
12041207
if (fragment.mHasMenu && fragment.mMenuVisible) {
12051208
mNeedMenuInvalidate = true;
12061209
}
1207-
moveToState(fragment, mCurState, transition, transitionStyle);
1210+
moveToState(fragment, mCurState, transition, transitionStyle, false);
12081211
}
12091212
}
12101213
}

0 commit comments

Comments
 (0)