Convert BackStackRecord Operations to ArrayList.

This slightly simplifies operations to add and remove operations
from the back stack by using an ArrayList instead of a custom
linked list.

Also removed fragments during replace are expanded into the
back stack to make the tracking of them simpler.

Change-Id: Ifac857396e4c6d42ddd44a3dc0f855649171e49c
This commit is contained in:
George Mount
2016-06-27 13:15:01 -07:00
parent fd9c9ee13d
commit f2045f8f0c

View File

@@ -54,39 +54,22 @@ final class BackStackState implements Parcelable {
final ArrayList<String> mSharedElementTargetNames;
public BackStackState(FragmentManagerImpl fm, BackStackRecord bse) {
int numRemoved = 0;
BackStackRecord.Op op = bse.mHead;
while (op != null) {
if (op.removed != null) {
numRemoved += op.removed.size();
}
op = op.next;
}
mOps = new int[bse.mNumOp * 7 + numRemoved];
final int numOps = bse.mOps.size();
mOps = new int[numOps * 6];
if (!bse.mAddToBackStack) {
throw new IllegalStateException("Not on back stack");
}
op = bse.mHead;
int pos = 0;
while (op != null) {
for (int opNum = 0; opNum < numOps; opNum++) {
final BackStackRecord.Op op = bse.mOps.get(opNum);
mOps[pos++] = op.cmd;
mOps[pos++] = op.fragment != null ? op.fragment.mIndex : -1;
mOps[pos++] = op.enterAnim;
mOps[pos++] = op.exitAnim;
mOps[pos++] = op.popEnterAnim;
mOps[pos++] = op.popExitAnim;
if (op.removed != null) {
final int N = op.removed.size();
mOps[pos++] = N;
for (int i = 0; i < N; i++) {
mOps[pos++] = op.removed.get(i).mIndex;
}
} else {
mOps[pos++] = 0;
}
op = op.next;
}
mTransition = bse.mTransition;
mTransitionStyle = bse.mTransitionStyle;
@@ -136,18 +119,6 @@ final class BackStackState implements Parcelable {
op.exitAnim = mOps[pos++];
op.popEnterAnim = mOps[pos++];
op.popExitAnim = mOps[pos++];
final int N = mOps[pos++];
if (N > 0) {
op.removed = new ArrayList<Fragment>(N);
for (int i = 0; i < N; i++) {
if (FragmentManagerImpl.DEBUG) {
Log.v(FragmentManagerImpl.TAG,
"Instantiate " + bse + " set remove fragment #" + mOps[pos]);
}
Fragment r = fm.mActive.get(mOps[pos++]);
op.removed.add(r);
}
}
bse.mEnterAnim = op.enterAnim;
bse.mExitAnim = op.exitAnim;
bse.mPopEnterAnim = op.popEnterAnim;
@@ -219,20 +190,15 @@ final class BackStackRecord extends FragmentTransaction implements
static final int OP_ATTACH = 7;
static final class Op {
Op next;
Op prev;
int cmd;
Fragment fragment;
int enterAnim;
int exitAnim;
int popEnterAnim;
int popExitAnim;
ArrayList<Fragment> removed;
}
Op mHead;
Op mTail;
int mNumOp;
ArrayList<Op> mOps = new ArrayList<>();
int mEnterAnim;
int mExitAnim;
int mPopEnterAnim;
@@ -320,13 +286,13 @@ final class BackStackRecord extends FragmentTransaction implements
}
}
if (mHead != null) {
if (!mOps.isEmpty()) {
writer.print(prefix);
writer.println("Operations:");
String innerPrefix = prefix + " ";
Op op = mHead;
int num = 0;
while (op != null) {
final int numOps = mOps.size();
for (int opNum = 0; opNum < numOps; opNum++) {
final Op op = mOps.get(opNum);
String cmdStr;
switch (op.cmd) {
case OP_NULL:
@@ -359,7 +325,7 @@ final class BackStackRecord extends FragmentTransaction implements
}
writer.print(prefix);
writer.print(" Op #");
writer.print(num);
writer.print(opNum);
writer.print(": ");
writer.print(cmdStr);
writer.print(" ");
@@ -380,25 +346,6 @@ final class BackStackRecord extends FragmentTransaction implements
writer.println(Integer.toHexString(op.popExitAnim));
}
}
if (op.removed != null && op.removed.size() > 0) {
for (int i = 0; i < op.removed.size(); i++) {
writer.print(innerPrefix);
if (op.removed.size() == 1) {
writer.print("Removed: ");
} else {
if (i == 0) {
writer.println("Removed:");
}
writer.print(innerPrefix);
writer.print(" #");
writer.print(i);
writer.print(": ");
}
writer.println(op.removed.get(i));
}
}
op = op.next;
num++;
}
}
}
@@ -434,18 +381,11 @@ final class BackStackRecord extends FragmentTransaction implements
}
void addOp(Op op) {
if (mHead == null) {
mHead = mTail = op;
} else {
op.prev = mTail;
mTail.next = op;
mTail = op;
}
mOps.add(op);
op.enterAnim = mEnterAnim;
op.exitAnim = mExitAnim;
op.popEnterAnim = mPopEnterAnim;
op.popExitAnim = mPopExitAnim;
mNumOp++;
}
public FragmentTransaction add(Fragment fragment, String tag) {
@@ -660,8 +600,9 @@ final class BackStackRecord extends FragmentTransaction implements
Log.v(TAG, "Bump nesting in " + this
+ " by " + amt);
}
Op op = mHead;
while (op != null) {
final int numOps = mOps.size();
for (int opNum = 0; opNum < numOps; opNum++) {
final Op op = mOps.get(opNum);
if (op.fragment != null) {
op.fragment.mBackStackNesting += amt;
if (FragmentManagerImpl.DEBUG) {
@@ -669,17 +610,6 @@ final class BackStackRecord extends FragmentTransaction implements
+ op.fragment + " to " + op.fragment.mBackStackNesting);
}
}
if (op.removed != null) {
for (int i = op.removed.size() - 1; i >= 0; i--) {
Fragment r = op.removed.get(i);
r.mBackStackNesting += amt;
if (FragmentManagerImpl.DEBUG) {
Log.v(TAG, "Bump nesting of "
+ r + " to " + r.mBackStackNesting);
}
}
}
op = op.next;
}
}
@@ -735,6 +665,7 @@ final class BackStackRecord extends FragmentTransaction implements
}
}
expandReplaceOps();
bumpBackStackNesting(1);
if (mManager.mCurState >= Fragment.CREATED) {
@@ -744,88 +675,38 @@ final class BackStackRecord extends FragmentTransaction implements
beginTransition(firstOutFragments, lastInFragments, false);
}
Op op = mHead;
while (op != null) {
final int numOps = mOps.size();
for (int opNum = 0; opNum < numOps; opNum++) {
final Op op = mOps.get(opNum);
Fragment f = op.fragment;
switch (op.cmd) {
case OP_ADD: {
Fragment f = op.fragment;
case OP_ADD:
f.mNextAnim = op.enterAnim;
mManager.addFragment(f, false);
}
break;
case OP_REPLACE: {
Fragment f = op.fragment;
int containerId = f.mContainerId;
if (mManager.mAdded != null) {
for (int i = mManager.mAdded.size() - 1; i >= 0; i--) {
Fragment old = mManager.mAdded.get(i);
if (FragmentManagerImpl.DEBUG) {
Log.v(TAG,
"OP_REPLACE: adding=" + f + " old=" + old);
}
if (old.mContainerId == containerId) {
if (old == f) {
op.fragment = f = null;
} else {
if (op.removed == null) {
op.removed = new ArrayList<Fragment>();
}
op.removed.add(old);
old.mNextAnim = op.exitAnim;
if (mAddToBackStack) {
old.mBackStackNesting += 1;
if (FragmentManagerImpl.DEBUG) {
Log.v(TAG, "Bump nesting of "
+ old + " to " + old.mBackStackNesting);
}
}
mManager.removeFragment(old, mTransition, mTransitionStyle);
}
}
}
}
if (f != null) {
f.mNextAnim = op.enterAnim;
mManager.addFragment(f, false);
}
}
break;
case OP_REMOVE: {
Fragment f = op.fragment;
break;
case OP_REMOVE:
f.mNextAnim = op.exitAnim;
mManager.removeFragment(f, mTransition, mTransitionStyle);
}
break;
case OP_HIDE: {
Fragment f = op.fragment;
break;
case OP_HIDE:
f.mNextAnim = op.exitAnim;
mManager.hideFragment(f, mTransition, mTransitionStyle);
}
break;
case OP_SHOW: {
Fragment f = op.fragment;
break;
case OP_SHOW:
f.mNextAnim = op.enterAnim;
mManager.showFragment(f, mTransition, mTransitionStyle);
}
break;
case OP_DETACH: {
Fragment f = op.fragment;
break;
case OP_DETACH:
f.mNextAnim = op.exitAnim;
mManager.detachFragment(f, mTransition, mTransitionStyle);
}
break;
case OP_ATTACH: {
Fragment f = op.fragment;
break;
case OP_ATTACH:
f.mNextAnim = op.enterAnim;
mManager.attachFragment(f, mTransition, mTransitionStyle);
}
break;
default: {
break;
default:
throw new IllegalArgumentException("Unknown cmd: " + op.cmd);
}
}
op = op.next;
}
mManager.moveToState(mManager.mCurState, mTransition,
@@ -836,6 +717,72 @@ final class BackStackRecord extends FragmentTransaction implements
}
}
private void expandReplaceOps() {
final int numOps = mOps.size();
boolean hasReplace = false;
// Before we do anything, check to see if any replace operations exist:
for (int opNum = 0; opNum < numOps; opNum++) {
final Op op = mOps.get(opNum);
if (op.cmd == OP_REPLACE) {
hasReplace = true;
break;
}
}
if (!hasReplace) {
return; // nothing to expand
}
ArrayList<Fragment> added = (mManager.mAdded == null) ? new ArrayList<Fragment>() :
new ArrayList<>(mManager.mAdded);
for (int opNum = 0; opNum < mOps.size(); opNum++) {
final Op op = mOps.get(opNum);
switch (op.cmd) {
case OP_ADD:
case OP_ATTACH:
added.add(op.fragment);
break;
case OP_REMOVE:
case OP_DETACH:
added.remove(op.fragment);
break;
case OP_REPLACE: {
Fragment f = op.fragment;
int containerId = f.mContainerId;
boolean alreadyAdded = false;
for (int i = added.size() - 1; i >= 0; i--) {
Fragment old = added.get(i);
if (old.mContainerId == containerId) {
if (old == f) {
alreadyAdded = true;
} else {
Op removeOp = new Op();
removeOp.cmd = OP_REMOVE;
removeOp.fragment = old;
removeOp.enterAnim = op.enterAnim;
removeOp.popEnterAnim = op.popEnterAnim;
removeOp.exitAnim = op.exitAnim;
removeOp.popExitAnim = op.popExitAnim;
mOps.add(opNum, removeOp);
added.remove(old);
opNum++;
}
}
}
if (alreadyAdded) {
mOps.remove(opNum);
opNum--;
} else {
op.cmd = OP_ADD;
added.add(f);
}
}
break;
}
}
}
private static void setFirstOut(SparseArray<Fragment> firstOutFragments,
SparseArray<Fragment> lastInFragments, Fragment fragment) {
if (fragment != null) {
@@ -889,30 +836,13 @@ final class BackStackRecord extends FragmentTransaction implements
if (!mManager.mContainer.onHasView()) {
return; // nothing to see, so no transitions
}
Op op = mHead;
while (op != null) {
final int numOps = mOps.size();
for (int opNum = 0; opNum < numOps; opNum++) {
final Op op = mOps.get(opNum);
switch (op.cmd) {
case OP_ADD:
setLastIn(firstOutFragments, lastInFragments, op.fragment);
break;
case OP_REPLACE: {
Fragment f = op.fragment;
if (mManager.mAdded != null) {
for (int i = 0; i < mManager.mAdded.size(); i++) {
Fragment old = mManager.mAdded.get(i);
if (f == null || old.mContainerId == f.mContainerId) {
if (old == f) {
f = null;
lastInFragments.remove(old.mContainerId);
} else {
setFirstOut(firstOutFragments, lastInFragments, old);
}
}
}
}
setLastIn(firstOutFragments, lastInFragments, op.fragment);
break;
}
case OP_REMOVE:
setFirstOut(firstOutFragments, lastInFragments, op.fragment);
break;
@@ -929,8 +859,6 @@ final class BackStackRecord extends FragmentTransaction implements
setLastIn(firstOutFragments, lastInFragments, op.fragment);
break;
}
op = op.next;
}
}
@@ -948,20 +876,13 @@ final class BackStackRecord extends FragmentTransaction implements
if (!mManager.mContainer.onHasView()) {
return; // nothing to see, so no transitions
}
Op op = mTail;
while (op != null) {
final int numOps = mOps.size();
for (int opNum = numOps - 1; opNum >= 0; opNum--) {
final Op op = mOps.get(opNum);
switch (op.cmd) {
case OP_ADD:
setFirstOut(firstOutFragments, lastInFragments, op.fragment);
break;
case OP_REPLACE:
if (op.removed != null) {
for (int i = op.removed.size() - 1; i >= 0; i--) {
setLastIn(firstOutFragments, lastInFragments, op.removed.get(i));
}
}
setFirstOut(firstOutFragments, lastInFragments, op.fragment);
break;
case OP_REMOVE:
setLastIn(firstOutFragments, lastInFragments, op.fragment);
break;
@@ -978,8 +899,6 @@ final class BackStackRecord extends FragmentTransaction implements
setFirstOut(firstOutFragments, lastInFragments, op.fragment);
break;
}
op = op.prev;
}
}
@@ -1689,74 +1608,44 @@ final class BackStackRecord extends FragmentTransaction implements
bumpBackStackNesting(-1);
Op op = mTail;
while (op != null) {
final int numOps = mOps.size();
for (int opNum = numOps - 1; opNum >= 0; opNum--) {
final Op op = mOps.get(opNum);
Fragment f = op.fragment;
switch (op.cmd) {
case OP_ADD: {
Fragment f = op.fragment;
case OP_ADD:
f.mNextAnim = op.popExitAnim;
mManager.removeFragment(f,
FragmentManagerImpl.reverseTransit(mTransition),
mTransitionStyle);
}
break;
case OP_REPLACE: {
Fragment f = op.fragment;
if (f != null) {
f.mNextAnim = op.popExitAnim;
mManager.removeFragment(f,
FragmentManagerImpl.reverseTransit(mTransition),
mTransitionStyle);
}
if (op.removed != null) {
for (int i = 0; i < op.removed.size(); i++) {
Fragment old = op.removed.get(i);
old.mNextAnim = op.popEnterAnim;
mManager.addFragment(old, false);
}
}
}
break;
case OP_REMOVE: {
Fragment f = op.fragment;
break;
case OP_REMOVE:
f.mNextAnim = op.popEnterAnim;
mManager.addFragment(f, false);
}
break;
case OP_HIDE: {
Fragment f = op.fragment;
break;
case OP_HIDE:
f.mNextAnim = op.popEnterAnim;
mManager.showFragment(f,
FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle);
}
break;
case OP_SHOW: {
Fragment f = op.fragment;
break;
case OP_SHOW:
f.mNextAnim = op.popExitAnim;
mManager.hideFragment(f,
FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle);
}
break;
case OP_DETACH: {
Fragment f = op.fragment;
break;
case OP_DETACH:
f.mNextAnim = op.popEnterAnim;
mManager.attachFragment(f,
FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle);
}
break;
case OP_ATTACH: {
Fragment f = op.fragment;
break;
case OP_ATTACH:
f.mNextAnim = op.popExitAnim;
mManager.detachFragment(f,
FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle);
}
break;
default: {
break;
default:
throw new IllegalArgumentException("Unknown cmd: " + op.cmd);
}
}
op = op.prev;
}
if (doStateMove) {
@@ -1843,7 +1732,7 @@ final class BackStackRecord extends FragmentTransaction implements
}
public boolean isEmpty() {
return mNumOp == 0;
return mOps.isEmpty();
}
public class TransitionState {