commitallowingstateloss 和commit的区别

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sumsear/article/details/77712128

前段时间有大佬反应在使用DialogFragment的时候使用show的时候有出现程序crash的问题,有大神给的解决方案是重写show方法,因为在show方法中实际调用的是FragmentTransaction的commit()方法,将其改用commitAllowingStateLoss就可以了。

其实这个问题到现在也在困扰我,那就是commit()方法和commitAllowingStateLoss方法,他们之间有啥区别?带着这个问题我们来看看FragmentTransaction的源码!

  /**
     * Schedules a commit of this transaction.  The commit does
     * not happen immediately; it will be scheduled as work on the main thread
     * to be done the next time that thread is ready.
     *
     * <p class="note">A transaction can only be committed with this method
     * prior to its containing activity saving its state.  If the commit is
     * attempted after that point, an exception will be thrown.  This is
     * because the state after the commit can be lost if the activity needs to
     * be restored from its state.  See {@link #commitAllowingStateLoss()} for
     * situations where it may be okay to lose the commit.</p>
     * 
     * @return Returns the identifier of this transaction's back stack entry,
     * if {@link #addToBackStack(String)} had been called.  Otherwise, returns
     * a negative number.
     */
    public abstract int commit();

    /**
     * Like {@link #commit} but allows the commit to be executed after an
     * activity's state is saved.  This is dangerous because the commit can
     * be lost if the activity needs to later be restored from its state, so
     * this should only be used for cases where it is okay for the UI state
     * to change unexpectedly on the user.
     */
    public abstract int commitAllowingStateLoss();

结果发现这货是个抽象类哈,既然是抽象类,那就一定有实现。找到commit()和commitAllowingStateLoss的实现瞅瞅!然后在BackStackState的内部类BackStackRecord中找到了这两货

  @Override
    public int commit() {
        return commitInternal(false);
    }

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

然后我们就看到了这样的一幕,然来这两货都调用的同一个方法 commitInternal   其区别仅仅是一个true和false,下面我们再去看看这个 commitInternal 里面究竟是怎么处理的这个 truefalse吧!

int commitInternal(boolean allowStateLoss) {
        if (mCommitted) throw new IllegalStateException("commit already called");
        if (FragmentManagerImpl.DEBUG) {
            Log.v(TAG, "Commit: " + this);
            LogWriter logw = new LogWriter(TAG);
            PrintWriter pw = new PrintWriter(logw);
            dump("  ", null, pw, null);
            pw.close();
        }
        mCommitted = true;
        if (mAddToBackStack) {
            mIndex = mManager.allocBackStackIndex(this);
        } else {
            mIndex = -1;
        }
        mManager.enqueueAction(this, allowStateLoss);
        return mIndex;
    }

看这个方法名应该是入了个队,具体怎么玩,先不管,进去看看再说!

/**
     * Adds an action to the queue of pending actions.
     *
     * @param action the action to add
     * @param allowStateLoss whether to allow loss of state information
     * @throws IllegalStateException if the activity has been destroyed
     */
    public void enqueueAction(OpGenerator 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<>();
            }
            mPendingActions.add(action);
            scheduleCommit();
        }
    }

看来一切的真相就在这个checkStateLoss中了,并且根据前文来看只有在我们调用commit方法时才会进入这个方法。进去看看,反正警察叔叔又不会请我去喝茶!

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调用onSaveInstanceState方法之后是不能执行commit函数的,再下面一个我暂时还没找到mNoTransactionsBecause这个字符串实在什么地方赋值的!看来还得继续研究研究。

那么我们用这commit()和commitAllowingStateLoss()两个函数应该怎么用呢?还是先有道词典一下这两个函数的注释吧!

commit:

安排该事务的提交。这一承诺不会立即发生;它将被安排在主线程上,以便在线程准备好的时候完成。

commitAllowingStateLoss:

与 commit类似,但允许在活动状态保存后执行提交。这是危险的,因为如果Activity需要从其状态恢复,那么提交就会丢失,因此,只有在用户可以意外地更改UI状态的情况下,才可以使用该提交。


万能的Google已经在代码里面告诉我们要如何去用了,具体怎么运用还是得看大家奇巧淫技了!

猜你喜欢

转载自blog.csdn.net/sumsear/article/details/77712128
今日推荐