Android 7.0以上 charles OpenSSLhttps抓包

Fragment中的 Fragment的FragmentTransaction 对应
commit()和commitAllowingStateLoss()以及commitNow()和commitNowAllowingStateLoss()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
fragmentManager = getSupportFragmentManager();

  lifeFragment1 = new FragmentLife();
Bundle bundle = new Bundle();
bundle.putString("extra_test", "FragmentLife1");
lifeFragment1.setArguments(bundle);

//其实是通过FragmentManagerImpl获取一个BackStackRecord,
// 只能在activity存储它的状态(onSaveInstanceState(),当用户要离开activity时)之前调用commit(),如果在存储状态之后调用commit(),将会抛出一个异常。
// 这是因为当activity再次被恢复时commit之后的状态将丢失。如果丢失也没关系,那么使用commitAllowingStateLoss()方法。
// commit和CommitNow都会抛出异常,如果在onSaveInstanceState()后执行的话。allowStateLoss=false,方法后面会执行检查checkStateLoss(),就是已经保存状态或stop的就会抛出异常IllegalStateException
// commitNow不允许addToBackStack,commitNow是不允许加入BackStack中去的,会将mAddToBackStack标志设置为false

//class BackStackRecord extends FragmentTransaction implements BackStackEntry, OpGenerator
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.add(R.id.fragment_container, lifeFragment1);
// transaction.addToBackStack("frag1"); //设置BackStackRecord的mAddToBackStack标志为true
//int类型的返回值,而commitNow是void类型返回值。
transaction.commit();
transaction.commitAllowingStateLoss();
//同commit一样调用内部的commitInternal()方法,只不过传递的参数不同,commitAllowStateLoss的allowStateLoss是true,允许丢失状态不做检查,所以不会抛异常。
//commit、commitAllowingStateLoss调用了FragmentManagerImpl.enqueueAction的方法,丢进线程队列中

transaction.commitNow();

这段代码我们经常写,会很熟悉。但有时我们可能会碰到一个异常,信息如下:

1
Caused by: java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState

大意是在activity的onSaveInstanceState调用后再commit的Transaction导致的异常。为了不抛出异常有人建议使用commitAllowingStateLoss来代替commit。

那么commit和commitAllowingStateLoss有什么区别?

1
2
3
4
5
6
7
public int commit() {
return commitInternal(false);
}

public int commitAllowingStateLoss() {
return commitInternal(true);
}

commit和commitAllowingStateLoss都调用了commitInternal()方法,只是一个传了false,一个传了true,接着往下看:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int commitInternal(boolean allowStateLoss) {
if (mCommitted) {
throw new IllegalStateException("commit already called");
}
......
mCommitted = true;
if (mAddToBackStack) {
mIndex = mManager.allocBackStackIndex(this);
} else {
mIndex = -1;
}
mManager.enqueueAction(this, allowStateLoss);
return mIndex;
}

主要是mManager.enqueueAction(this, allowStateLoss)来执行这个任务,根据传入的参数继续往下走,可以看到:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public void enqueueAction(Runnable action, boolean allowStateLoss) {
if (!allowStateLoss) {
checkStateLoss();
}
synchronized (this) {
if (mDestroyed || mHost == null) {
throw new IllegalStateException("Activity has been destroyed");
}
if (mPendingActions == null) {
mPendingActions = new ArrayList<Runnable>();
}
mPendingActions.add(action);
if (mPendingActions.size() == 1) {
mHost.getHandler().removeCallbacks(mExecCommit);
mHost.getHandler().post(mExecCommit);
}
}
}

可以看到最开始传进来的allowStateLoss在这里只做了检查状态的操作;

1
2
3
4
5
6
7
8
private void checkStateLoss() {
if (mStateSaved) {
throw new IllegalStateException("Can not perform this action after onSaveInstanceState");
}
if (mNoTransactionsBecause != null) {
throw new IllegalStateException("Can not perform this action inside of " + mNoTransactionsBecause);
}
}

如果activity的状态被保存了,这里再提交就会检查这个状态,符合这个条件就抛出一个异常来终止应用进程。也就是说在activity调用了onSaveInstanceState()之后,再commit一个事务就会出现该异常。那如果不想抛出异常,也可以很简单调用commitAllowingStateLoss()方法来略过这个检查就可以了,但是这是危险的,如果activity随后需要从它保存的状态中恢复,这个commit是会丢失的。因此它仅仅适用在ui状态的改变对用户来说是可以接受的,允许丢失一部分状态。

总结:

1.在Activity的生命周期方法中提交事务要小心,越早越好,比如onCreate。尽量避免在onActivityResult()方法中提交。
2.避免在异步的回调方法中执行commit,因为他们感知不到当前Activity生命周期的状态。
3.使用commitAllowingStateLoss()代替commit()。相比于异常crash,UI状态的改变对用户来说是可以接受的。
4.如果你需要在Activity执行完onSaveInstanceState()之后还要进行提交,而且不关心恢复时是否会丢失此次提交,那么可以使用commitAllowingStateLoss()或commitNowAllowingStateLoss()。

2、 commitNow以及commitNowAllowingstateLoss()

在API_24版本FragmentTranslation里添加了该两个方法:

下面拿commitNow为例:
1
2
3
4
   public void commitNow() {
this.disallowAddToBackStack();
this.mManager.execSingleAction(this, false);
}

该方法不支持加入BackStack回退栈中,disallowAddToBackStack()。

  源码没有再使用Handler,而是直接执行(源码如下)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public void execSingleAction(FragmentManagerImpl.OpGenerator action, boolean allowStateLoss) {
if (!allowStateLoss || this.mHost != null && !this.mDestroyed) {
this.ensureExecReady(allowStateLoss);
if (action.generateOps(this.mTmpRecords, this.mTmpIsPop)) {
this.mExecutingActions = true;

try {
this.removeRedundantOperationsAndExecute(this.mTmpRecords, this.mTmpIsPop);
} finally {
this.cleanupExec();
}
}

this.doPendingDeferredStart();
this.burpActive();
}
}

官方更推荐使用commitNow()和commitNowAllowingStateLoss()来代替先执行commit()/commitAllowingStateLoss()