我们平时使用fragment, 都是先获取到FragmentManager, 再通过FragmentManager获取到FragmentTransaction, 然后通过FragmentTransaction对象进行对fragment的一些add, remove, show, hide等一系列操作, 最后将此FragmentTransaction对象commit, 就完成相应的操作了. 可是我发现同一个FragmentTransaction在进行两次commit的时候, 应用会崩溃, 抛出的异常信息是
commit already called
事出无常必为妖, 于是我开始向源码中寻求原因.
因为获取FragmentTransaction对象是通过beginTransaction()获取的, 先点击看这个方法里面的内容, 但是很可惜的看到FragmentManager类是一个抽象类, 且beginTransaction方法是一个抽象方法, 具体的实现逻辑不在里面, 然后就开始找它的实现类, 目标看向了getSupportFragmentManager方法, 因为我当前是继承的FragmentActivity, 我点击进入了FragmentActivity的getSupportFragmentManager()方法
经过一层一层的跳转, 我最终看到FragmentManager的实现类为FragmentManagerImpl, 在该类中寻找beginTransaction方法,
public FragmentTransaction beginTransaction() {
return new BackStackRecord(this);
}
我们看到该方法返回的是一个BackStackRecord实例化对象, 我们要找的commit方法就在这个类里, 找到commit方法,
public int commit() {
return this.commitInternal(false);
}
它最终调用的是commitInternal方法,
int commitInternal(boolean allowStateLoss) {
if (this.mCommitted) {
throw new IllegalStateException("commit already called");
} else {
if (FragmentManagerImpl.DEBUG) {
Log.v("FragmentManager", "Commit: " + this);
LogWriter logw = new LogWriter("FragmentManager");
PrintWriter pw = new PrintWriter(logw);
this.dump(" ", (FileDescriptor)null, pw, (String[])null);
pw.close();
}
this.mCommitted = true;
if (this.mAddToBackStack) {
this.mIndex = this.mManager.allocBackStackIndex(this);
} else {
this.mIndex = -1;
}
this.mManager.enqueueAction(this, allowStateLoss);
return this.mIndex;
}
}
该类有一个叫mCommitted的布尔值, 初始化的值是false, 当调用一遍commitInternal后, 将其赋值为true, 再以后调用的时候都只是抛一个内容为"commit already called"的IllegalStateException.
故, 我们使用FragmentTransaction时, 每次beginTransaction得到的对象只能进行一次commit.
要进行第二次commit时只能再次通过beginTransaction得到新的FragmentTransaction对象.