zoukankan      html  css  js  c++  java
  • FragmentTransaction的commit和commitAllowingStateLoss的差别

    1、什么是FragmentTransaction?

    使用Fragment时。能够通过用户交互来运行一些动作。比方添加、移除、替换等。

    全部这些改变构成一个集合,这个集合被叫做一个transaction。

    能够调用FragmentTransaction中的方法来处理这个transaction,而且能够将transaction存进由activity管理的back stack中,这样用户就能够进行fragment变化的回退操作。

    能够这样得到FragmentTransaction类的实例:

    FragmentManager  mFragmentManager = getSupportFragmentManager();
    FragmentTransaction  mFragmentTransaction = mFragmentManager.beginTransaction();

    2、commit和executePendingTransactions的差别

    用add(), remove(), replace()方法,把全部须要的变化加进去,然后调用commit()方法。将这些变化应用。


    在commit()方法之前,你能够调用addToBackStack(),把这个transaction增加back stack中去,这个back stack是由activity管理的。当用户按返回键时,就会回到上一个fragment的状态。
    你仅仅能在activity存储它的状态(当用户要离开activity时)之前调用commit()。假设在存储状态之后调用commit()。将会抛出一个异常。


    这是由于当activity再次被恢复时commit之后的状态将丢失。假设丢失也没关系。那么使用commitAllowingStateLoss()方法。

    3、问什么在存储状态之后调用commit会报异常?

    我们查看Android源代码发现FragmentManager和FragmentTransaction是一个虚类
    那他们在activity中的实例化代码是怎样处理的呢?
    首先是getSupportFragmentManager的方法
    /**
         * Return the FragmentManager for interacting with fragments associated
         * with this activity.
         */
        public FragmentManager getSupportFragmentManager() {
            return mFragments;
        }


    查找到mFragments。
    final FragmentManagerImpl mFragments = new FragmentManagerImpl();
    我们发现FragmentManagerImpl是继承于FragmentManager的一个实体类
    /**
     * Container for fragments associated with an activity.
     */
    final class FragmentManagerImpl extends FragmentManager {
        
        ........
    
    
        @Override
        public FragmentTransaction beginTransaction() {
            return new BackStackRecord(this);
        }
    
    
        ........
    
    
        }


    为了简便我们删除了一些不要的代码仅仅留下关键的方法。
    通过这段代码。我们能够查看到beginTransaction方法实际返回的是一个继承于FragmentTransaction的BackStackRecord类
    我们来查看BackStackRecord的代码,查看他的使用方法
    /**
     * @hide Entry of an operation on the fragment back stack.
     */
    final class BackStackRecord extends FragmentTransaction implements
            FragmentManager.BackStackEntry, Runnable {
    
    
    	..........
    	public int commit() {
            return commitInternal(false);
        }
    
    
        public int commitAllowingStateLoss() {
            return commitInternal(true);
        }
    
    
    	int commitInternal(boolean allowStateLoss) {
            if (mCommitted) throw new IllegalStateException("commit already called");
            if (FragmentManagerImpl.DEBUG) Log.v(TAG, "Commit: " + this);
            mCommitted = true;
            if (mAddToBackStack) {
                mIndex = mManager.allocBackStackIndex(this);
            } else {
                mIndex = -1;
            }
            mManager.enqueueAction(this, allowStateLoss);
            return mIndex;
        }
    	..........
    
    
    }


    绕了大半天,最终找到commit方法和commitAllowingStateLoss方法,他们都同一时候调用了commitInternal方法,仅仅是传的參数略有不同。一个是true。一个是false。我们发如今运行这种方法之前会首先对mCommitted进行推断,依据代码语义我们能够知道mCommitted就是是否已经commit的意思
    最后,commitInternal调用了mManager.enqueueAction的方法。

    让我们回到FragmentManager,看这种方法是怎样操作的。

    我们找到这种方法。

    /**
     * @hide Entry of an operation on the fragment back stack.
     */
    final class BackStackRecord extends FragmentTransaction implements
            FragmentManager.BackStackEntry, Runnable {
    
    
    	..........
    	public int commit() {
            return commitInternal(false);
        }
    
    
        public int commitAllowingStateLoss() {
            return commitInternal(true);
        }
    
    
    	int commitInternal(boolean allowStateLoss) {
            if (mCommitted) throw new IllegalStateException("commit already called");
            if (FragmentManagerImpl.DEBUG) Log.v(TAG, "Commit: " + this);
            mCommitted = true;
            if (mAddToBackStack) {
                mIndex = mManager.allocBackStackIndex(this);
            } else {
                mIndex = -1;
            }
            mManager.enqueueAction(this, allowStateLoss);
            return mIndex;
        }
    	..........
    
    
    }


    经分析后,我们能够发现。此方法在对 commit和commitAllowingStateLoss的传參进行推断后。将任务扔进activity的线程队列中。那这个两个方法差别就在传參推断后的处理方法checkStateLoss,那接下来,让我们查看一下checkStateLoss方法。看对參数进行推断后,做了什么样的处理。


    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);
            }
        }


    ok,到这里。真相总算大明。当使用commit方法时,系统将进行状态推断,假设状态(mStateSaved)已经保存,将发生"Can not perform this action after onSaveInstanceState"错误。
    假设mNoTransactionsBecause已经存在,将发生"Can not perform this action inside of " + mNoTransactionsBecause错误。

  • 相关阅读:
    win10下vs2015配置Opencv3.1.0过程详解
    Int16, Int32, Int64 范围
    Microsoft Language and Locale Codes(微软语言和地区代码汇总)
    Azure china服务状态报告查看网址
    Azure IOT (EventHub + Stream Analytics + Table Storage)的使用
    java 继承extends 的相关知识点
    final
    java 垃圾回收机制
    Java 抽象类
    重载与重写、多态——java
  • 原文地址:https://www.cnblogs.com/mfmdaoyou/p/7045243.html
Copyright © 2011-2022 走看看