今天准备写写Fragment的回退栈管理策略。
为了更好的理解本篇博客的内容。大家最好先看看我的另一篇博客:Fragment加载过程分析。
下面是Fragment的回退栈使用方法的代码:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
findViewById(R.id.addBackStack).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//添加Fragment到id为root的ViewGroup。并将其加入回退栈
getSupportFragmentManager().beginTransaction()
.addToBackStack(null)
.add(R.id.root, new TestFragment()).commit();
}
});
findViewById(R.id.popBackStack).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//从回退栈里弹出最新加入的Fragment
getSupportFragmentManager().popBackStackImmediate();
}
});
}
在上面的代码中。我在界面加入两个按钮。一个点击后将TestFragment加入回退栈。一个点击后将新加入的TestFragment从Fragment的回退栈中弹出。
要让添加的Fragment加入回退栈。需要记住,调用addToBackStack(String)方法必须在commit()方法之前。让Fragment从回退栈中弹栈的方法。有两种。一种就是上面用的popBackStackImmediate()方法。另一种是popBackStack(),它们的区别稍微会有详细的讲解。
首先说让Fragment的入栈操作。需要在commit()方法前调用addToBackStack()方法。下面我们来看此方法。此方法定义在BackStackRecord类中。它是FragmentTransaction的子类。也就是用于Fragment事务管理的类。
public FragmentTransaction addToBackStack(String name) {
if (!mAllowAddToBackStack) {
throw new IllegalStateException(
"This FragmentTransaction is not allowed to be added to the back stack.");
}
mAddToBackStack = true;
mName = name;
return this;
}
在这个方法中。我们可以看到。它只是简单的将mAddToBackStack 标志位设为true。再保存当前Fragment的tag名。现在我们注意到。在最外层有一个mAllowAddToBackStack标志位。代表是否允许加入回退栈。若你不想它加入回退栈。可以调用 disallowAddToBackStack()方法,接着在我们提交此次添加操作时。调用了commitInternal()方法。它的调用层次为commit()--->commitInternal():
int commitInternal(boolean allowStateLoss) {
if (mCommitted) throw new IllegalStateException("commit already called");
if (FragmentManagerImpl.DEBUG) {
Log.v(TAG, "Commit: " + this);
LogWriter logw = new LogWriter(TAG);
PrintWriter pw = new PrintWriter(logw);
dump(" ", null, pw, null);
}
mCommitted = true;
if (mAddToBackStack) {
mIndex = mManager.allocBackStackIndex(this);
} else {
mIndex = -1;
}
mManager.enqueueAction(this, allowStateLoss);
return mIndex;
}
在第11行。当此Fragment要求入栈的时候。会由FargmentManager为它分配一个索引下标值。代表此次提交会将此组Fragment放于栈中的第几层。最下层的索引下标为0。接着往下。到BackStackRecord类中的run方法中:
public void run() {
......
if (mAddToBackStack) {
mManager.addBackStackState(this);
}
}
这里直接调用addBackStackState()方法。跟进去!
void addBackStackState(BackStackRecord state) {
if (mBackStack == null) {