Android碎片事务提交transaction.commit()和transaction.commitnow()的区别以及源码完全解析
来源:互联网 发布:画设计图用什么软件 编辑:程序博客网 时间:2024/06/05 16:11
先普及一个知识
当你调用了碎片空的构造器的时候,你的碎片并不会执行生命周期的方法,如onCreateView()等
什么时候会执行生命周期呢?
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.add(mContainerId, mFragment);
transaction.commit();
当你把这个碎片add进fragmentmanager(碎片栈),或者replace(是remove和add的结合体)进去的时候,你才会进入碎片的生命周期。既然commit就可以进入碎片的生命周期那commitNow又是做什么用的?
顾名思义,commitNow就是立刻提交事务,那也不难推断出commit其实提交后,并没有立刻执行你所期待的操作。
那么什么时候执行呢?他们的具体区别到底在哪呢?我用一个实例分析一下。
NavFragment navFragment = new NavFragment();addFragment(R.id.fl_nav, navFragment);navFragment.setup();如果你的addFragment里的事务提交是commit方法,那么你的执行流程是这样的:虽然你addFragment方法里你commit了,但是commit是会被搁置的,当你活动中接下来的所有初始化代码执行完以后,才会去真正执行把碎片add进fragmentmanager的栈中,并且执行碎片一系列的生命周期操作。
如果你的addFragment里的事务提交是commitNow方法,那你的执行流程是这样的:先把碎片那一系列的生命周期操作执行了,让你的碎片真正被“激活”了,才会按顺序执行你activity中的余下代码。
我们先追溯一下commit的源码,在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();
你会惊讶的发现commit是一个抽象方法,并且附上了一段密密麻麻的注释。先不急找到这个方法的实现类,我们采用谷歌翻译对注释进行翻译抽取有用的信息。
计划提交此事务。提交确实不是马上发生;它将被安排在主线程上工作,待下次线程准备完成。
后面是讲到如果是因为你活动需要执行了这个commit,那么你在排队的过程中信息有可能会丢失,但是可以从存储的状态中恢复(没啥用)
经过寻找,BackStackRecord是FragmenTransaction的实现类。我们定位commit的方法
@Overridepublic int commit() { return commitInternal(false);}
继续寻找commitInternal方法
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;}上面的debug不用看,看一下if语句里的,mIndex = mManager.allocBackStackIndex(this);意思就是取得当前回退栈中的序列号返回,其实也不用多关注,我们需要关注的是mManager.enqueueAction(this, allowStateLoss);方法。
我们再度定位一下enqueueAction方法
/** * 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(); }}看一下传进来的第一个参数,有些人可能很好奇,我们传的是this,就是把BackStackRecord的实例传进来了,怎么回是这样一个对象?难道BackStackRecord实现了这个接口?
final FragmentManagerImpl mManager;
并没有,在那里的上下文是这个mManager,可以倒回去看一下,这个FragmentManager的实现类实现了OpGenerater这个接口。那就是把我们当前的操作传了进来(比如add碎片进栈,remove出栈,detach解除联系之类的操作)
ArrayList<OpGenerator> mPendingActions;
mPendingActions.add(action);scheduleCommit();这里第一句话就是把这个action进入等待序列中,其实就是用一个arrayList把操作存进去,等待执行。
然后下一行就是规划这个action的执行时间了。
继续追溯scheduleCommit()
/** * Schedules the execution when one hasn't been scheduled already. This should happen * the first time {@link #enqueueAction(OpGenerator, boolean)} is called or when * a postponed transaction has been started with * {@link Fragment#startPostponedEnterTransition()} */private void scheduleCommit() { synchronized (this) { boolean postponeReady = mPostponedTransactions != null && !mPostponedTransactions.isEmpty(); boolean pendingReady = mPendingActions != null && mPendingActions.size() == 1; if (postponeReady || pendingReady) { mHost.getHandler().removeCallbacks(mExecCommit); mHost.getHandler().post(mExecCommit); } }}Handler可以用来更新UI,也可以用来发送消息、处理消息。
道理我们都懂,那么mExecCommit的具体代码又是怎样的?
Runnable mExecCommit = new Runnable() { @Override public void run() { execPendingActions(); }};这就很清晰了,开了一个子线程来执行等待队列里的操作。我们就是传一个子线程的实现给handler的post方法。
追溯post方法,这里就进入到我们熟悉的领域了
/** * Causes the Runnable r to be added to the message queue. * The runnable will be run on the thread to which this handler is * attached. * * @param r The Runnable that will be executed. * * @return Returns true if the Runnable was successfully placed in to the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. */public final boolean post(Runnable r){ return sendMessageDelayed(getPostMessage(r), 0);}所以我们线程在这里被执行
追溯sendMessageDelayed
/** * Enqueue a message into the message queue after all pending messages * before (current time + delayMillis). You will receive it in * {@link #handleMessage}, in the thread attached to this handler. * * @return Returns true if the message was successfully placed in to the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. Note that a * result of true does not mean the message will be processed -- if * the looper is quit before the delivery time of the message * occurs then the message will be dropped. */public final boolean sendMessageDelayed(Message msg, long delayMillis){ if (delayMillis < 0) { delayMillis = 0; } return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);}
然后就把东西放到消息队列里,在设定的时间间隔后开始执行。不讲了,又是一系列出入队列的操作。
下面看看commitNow的源码,明白和commit的区别
翻译:同步执行这个事务,就是立刻执行,所有被加入的碎片都会被立刻完成生命周期状态,所以移除的碎片都会被撕碎。* Commits this transaction synchronously. Any added fragments will be* initialized and brought completely to the lifecycle state of their host* and any removed fragments will be torn down accordingly before this* call returns
* <p>Transactions committed in this way may not be added to the* FragmentManager's back stack, as doing so would break other expected* ordering guarantees for other asynchronously committed transactions.翻译:以这种方式提交的交易可能不会被添加到FragmentManager的回退栈,这样做会破坏其他想要异步提交的事务(指代的就是commit,异步提交的事务)
追溯commitNow
@Overridepublic void commitNow() { disallowAddToBackStack(); mManager.execSingleAction(this, false);}disallowAddToBackStack();佐证了观点上面翻译里的观点,不允许添加到回退栈中。
所以我们要执行execSingleAction,开始主线程里跑这个事务提交了
追溯execSingleAction
public void execSingleAction(OpGenerator action, boolean allowStateLoss) { ensureExecReady(allowStateLoss); if (action.generateOps(mTmpRecords, mTmpIsPop)) { mExecutingActions = true; try { optimizeAndExecuteOps(mTmpRecords, mTmpIsPop); } finally { cleanupExec(); } } doPendingDeferredStart();}
一开始我被误导了,以为optimizeAndExecuteOps才是执行commitNow的方法,其实这个方法是进行commitNow完成后的扫尾操作。因为commitNow直接在主线程提交的事务,所以是一种线程不安全的操作,并且影响了其他的transaction,所以后面的都是对其进行扫尾和优化的工作。
真正的执行
action.generateOps(mTmpRecords, mTmpIsPop)
所以是在这个接口的实现类里跑的。
/** * An add or pop transaction to be scheduled for the UI thread. */interface OpGenerator { /** * Generate transactions to add to {@code records} and whether or not the transaction is * an add or pop to {@code isRecordPop}. * * records and isRecordPop must be added equally so that each transaction in records * matches the boolean for whether or not it is a pop in isRecordPop. * * @param records A list to add transactions to. * @param isRecordPop A list to add whether or not the transactions added to records is * a pop transaction. * @return true if something was added or false otherwise. */ boolean generateOps(ArrayList<BackStackRecord> records, ArrayList<Boolean> isRecordPop);}
具体实现是在哪呢?我也不知道啊,继承还能找找,这个我上哪去找啊。反正就是在这里执行的commitNow是跑不了的。
最后我找到了这个接口的实现,是在BackStackRecord中重写的。
/** * Implementation of {@link FragmentManagerImpl.OpGenerator}. * This operation is added to the list of pending actions during {@link #commit()}, and * will be executed on the UI thread to run this FragmentTransaction. * * @param records Modified to add this BackStackRecord * @param isRecordPop Modified to add a false (this isn't a pop) * @return true always because the records and isRecordPop will always be changed */@Overridepublic boolean generateOps(ArrayList<BackStackRecord> records, ArrayList<Boolean> isRecordPop) { if (FragmentManagerImpl.DEBUG) { Log.v(TAG, "Run: " + this); } records.add(this); isRecordPop.add(false); if (mAddToBackStack) { mManager.addBackStackState(this); } return true;}
- Android碎片事务提交transaction.commit()和transaction.commitnow()的区别以及源码完全解析
- 【DB.Oracle】事务transaction的隐式提交commit
- Hibernate中Transaction事务的批量提交
- 事务的理解transaction
- 事务(Transaction)的特性和状态
- 论hibernate中的session.flush()和transaction.commit()的差异
- session.flush与transaction.commit 区别
- Transaction 事务
- Transaction-事务
- 事务Transaction
- Transaction事务
- 事务(Transaction)
- Transaction 事务
- 事务(Transaction)
- 事务Transaction
- 事务Transaction()详解(以及ContentValue的注意点)
- hibernate,session.save(entity)和transaction.commit()
- [第4篇]System.Transactions事务之事务(Transaction)和可提交事务(CommittableTransaction)
- 11.18--多对多关联映射
- MATLAB中ezplot函数
- 指令系统
- C#算法系列(4)——简单排序算法小结
- 宏定义中的特殊参数(#、##、...和__VA_ARGS__)
- Android碎片事务提交transaction.commit()和transaction.commitnow()的区别以及源码完全解析
- HTML-图像的使用(img标签和map标签的使用)
- 算法笔记1
- 使用Thumbnails压缩图片
- 数组中的逆序数(用到归并排序)
- OpenGL:将绘制场景保存为bmp图片
- 【资料合集】阿里巴巴开源技术汇总——内含115个软件与100+技术文档、PDF下载
- 低层视觉:使用一幅图像——纹理
- 统计学习方法——模型的选择与评估(过拟合、泛化能力)