zoukankan      html  css  js  c++  java
  • Fragment的FragmentTransaction 的commit()和commitAllowingStateLoss()以及commitNow()和commitNowAllowingStateLoss()

    android开发中肯定用到过Fragment

     1      fragmentManager = getSupportFragmentManager();
     2 
     3       lifeFragment1 = new FragmentLife();
     4         Bundle bundle = new Bundle();
     5         bundle.putString("extra_test", "FragmentLife1");
     6         lifeFragment1.setArguments(bundle);
     7 
     8         //其实是通过FragmentManagerImpl获取一个BackStackRecord,
     9 //        只能在activity存储它的状态(onSaveInstanceState(),当用户要离开activity时)之前调用commit(),如果在存储状态之后调用commit(),将会抛出一个异常。
    10 //        这是因为当activity再次被恢复时commit之后的状态将丢失。如果丢失也没关系,那么使用commitAllowingStateLoss()方法。
    11 //        commit和CommitNow都会抛出异常,如果在onSaveInstanceState()后执行的话。allowStateLoss=false,方法后面会执行检查checkStateLoss(),就是已经保存状态或stop的就会抛出异常IllegalStateException
    12 //        commitNow不允许addToBackStack,commitNow是不允许加入BackStack中去的,会将mAddToBackStack标志设置为false
    13 
    14         //class BackStackRecord extends FragmentTransaction implements BackStackEntry, OpGenerator
    15         FragmentTransaction transaction = fragmentManager.beginTransaction();
    16         transaction.add(R.id.fragment_container, lifeFragment1);
    17 //        transaction.addToBackStack("frag1"); //设置BackStackRecord的mAddToBackStack标志为true
    18         //int类型的返回值,而commitNow是void类型返回值。
    19         transaction.commit();
    20         transaction.commitAllowingStateLoss();
    21         //同commit一样调用内部的commitInternal()方法,只不过传递的参数不同,commitAllowStateLoss的allowStateLoss是true,允许丢失状态不做检查,所以不会抛异常。
    22         //commit、commitAllowingStateLoss调用了FragmentManagerImpl.enqueueAction的方法,丢进线程队列中
    23 
    24         transaction.commitNow();  

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

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

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

    那么commit和commitAllowingStateLoss有什么区别?

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

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

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

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

     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 }

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

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


    如果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()

    二、 commitNow以及commitNowAllowingstateLoss()

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

           下面拿commitNow为例: 

    1   public void commitNow() {
    2         this.disallowAddToBackStack();
    3         this.mManager.execSingleAction(this, false);
    4     }

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

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

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

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

  • 相关阅读:
    Codeforces 1265A Beautiful String
    1039 Course List for Student (25)
    1038 Recover the Smallest Number (30)
    1037 Magic Coupon (25)
    1024 Palindromic Number (25)
    1051 Pop Sequence (25)
    1019 General Palindromic Number (20)
    1031 Hello World for U (20)
    1012 The Best Rank (25)
    1011 World Cup Betting (20)
  • 原文地址:https://www.cnblogs.com/linghu-java/p/12176933.html
Copyright © 2011-2022 走看看