[关闭]
@act262 2017-05-24T14:19:32.000000Z 字数 3421 阅读 1415

Fragment的commit分析

Android


一般使用的Fragment方式

  1. FragmentManager manager = getFragmentManager();
  2. FragmentTransaction transaction = manager.beginTransaction();
  3. transaction.show(fragment);
  4. transaction.commit();
  5. // 或者状态丢失的提交
  6. transaction.commitAllowingStateLoss();

有时候会遇到Crash,大概意思是在状态保存后不能提交事务操作。

  1. IllegalStateException: Can not perform this action after onSaveInstanceState at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1493) at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1511) at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:638) at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:617)

从异常的堆栈信息分析开始,调用FragmentTransactioncommit方法

FragmentTranstraction.commit() -> FragmentManager.enqueueAction() -> FragmentManager.checkStateLoss()

FragmentTranstraction的实现类 BackStackRecord的具体方法实现

  1. public int commit() {
  2. return commitInternal(false);
  3. }
  4. public int commitAllowingStateLoss() {
  5. return commitInternal(true);
  6. }
  7. int commitInternal(boolean allowStateLoss) {
  8. if (mCommitted) throw new IllegalStateException("commit already called");
  9. if (FragmentManagerImpl.DEBUG) {
  10. Log.v(TAG, "Commit: " + this);
  11. LogWriter logw = new LogWriter(TAG);
  12. PrintWriter pw = new PrintWriter(logw);
  13. dump(" ", null, pw, null);
  14. }
  15. mCommitted = true;
  16. if (mAddToBackStack) {
  17. mIndex = mManager.allocBackStackIndex(this);
  18. } else {
  19. mIndex = -1;
  20. }
  21. mManager.enqueueAction(this, allowStateLoss);
  22. return mIndex;
  23. }

FragmentManager的实现类FragmentManagerImpl

  1. public void enqueueAction(Runnable action, boolean allowStateLoss) {
  2. if (!allowStateLoss) {
  3. checkStateLoss();
  4. }
  5. synchronized (this) {
  6. if (mDestroyed || mHost == null) {
  7. throw new IllegalStateException("Activity has been destroyed");
  8. }
  9. if (mPendingActions == null) {
  10. mPendingActions = new ArrayList<Runnable>();
  11. }
  12. mPendingActions.add(action);
  13. if (mPendingActions.size() == 1) {
  14. mHost.getHandler().removeCallbacks(mExecCommit);
  15. mHost.getHandler().post(mExecCommit);
  16. }
  17. }
  18. }
  19. private void checkStateLoss() {
  20. if (mStateSaved) {
  21. throw new IllegalStateException(
  22. "Can not perform this action after onSaveInstanceState");
  23. }
  24. if (mNoTransactionsBecause != null) {
  25. throw new IllegalStateException(
  26. "Can not perform this action inside of " + mNoTransactionsBecause);
  27. }
  28. }

所以关键的是找到mStateSaved这个标记的变化的代码,
FragmentManager的实现类FragmentManagerImplsaveAllState中对其标记为true

  1. Parcelable saveAllState() {
  2. // Make sure all pending operations have now been executed to get
  3. // our state update-to-date.
  4. execPendingActions();
  5. // android.os.Build.VERSION.SDK_INT >= 11;
  6. if (HONEYCOMB) {
  7. // As of Honeycomb, we save state after pausing. Prior to that
  8. // it is before pausing. With fragments this is an issue, since
  9. // there are many things you may do after pausing but before
  10. // stopping that change the fragment state. For those older
  11. // devices, we will not at this point say that we have saved
  12. // the state, so we will allow them to continue doing fragment
  13. // transactions. This retains the same semantics as Honeycomb,
  14. // though you do have the risk of losing the very most recent state
  15. // if the process is killed... we'll live with that.
  16. mStateSaved = true;
  17. }
  18. //....
  19. }

saveAllState方法在FragmentActivity 的onSaveInstanceState被调用

  1. /**
  2. * Save all appropriate fragment state.
  3. */
  4. @Override
  5. protected void onSaveInstanceState(Bundle outState) {
  6. super.onSaveInstanceState(outState);
  7. Parcelable p = mFragments.saveAllState();
  8. if (p != null) {
  9. outState.putParcelable(FRAGMENTS_TAG, p);
  10. }
  11. }

FragmentController的saveAllState方法

  1. public Parcelable saveAllState() {
  2. return mHost.mFragmentManager.saveAllState();
  3. }

最后再调用到FragmentManager的saveAllState

为了状态的正常保存和恢复,在Activity的状态保存后不能再提交事务了,
要么选择使用commitAllowingStateLoss来避免崩溃,或者在commit之前先调用FragmentManager.noteStateNotSaved来把状态改为false

  1. public void noteStateNotSaved() {
  2. mStateSaved = false;
  3. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注