丈夫志四海,万里犹比邻。这篇文章主要讲述[Android]Fragment源代码分析 事务相关的知识,希望能为你提供帮助。
Fragment管理中,不得不谈到的就是它的事务管理,它的事务管理写的很的出彩。我们先引入一个简单经常使用的Fragment事务管理代码片段:
FragmentTransaction ft = this.getSupportFragmentManager().beginTransaction(); ft.add(R.id.fragmentContainer, fragment, " tag" ); ft.addToBackStack(" < span style=" font-family: Arial, Helvetica, sans-serif; " > tag< /span> < span style=" font-family: Arial, Helvetica, sans-serif; " > " ); < /span> ft.commitAllowingStateLoss();
这段代码运行过后,就能够往fragmentContainer控件中增加Fragment的内部持有控件。
上一讲我们说到Fragment通过状态机的变更来生成内部的mView。当你使用的是非from layout.xml方式的时候,它会在Fragment.CREATED状态下搜索container相应的控件然后将mView增加到这个父控件中。
那么这个事务又在这里面承担什么样的作用呢?
我们先来看Manager.beginTransaction这种方法的返回值 :
/** * Start a series of edit operations on the Fragments associated with this * FragmentManager. * * < p> * Note: A fragment transaction can only be created/committed prior to an * activity saving its state. If you try to commit a transaction after * {@link FragmentActivity#onSaveInstanceState * FragmentActivity.onSaveInstanceState()} (and prior to a following * {@link FragmentActivity#onStart FragmentActivity.onStart} or * {@link FragmentActivity#onResume FragmentActivity.onResume()}, you will * get an error. This is because the framework takes care of saving your * current fragments in the state, and if changes are made after the state * is saved then they will be lost. * < /p> */ public abstract FragmentTransaction beginTransaction();
在Fragment的管理中FragmentManager的实现类是FragmentManagerImpl,当然这也是android一贯的命名方式;
FragmentManagerImpl.java: @Override public FragmentTransaction beginTransaction() { return new BackStackRecord(this); }
FragmentManager通过返回一个叫做BackStackRecord的对象完毕事务处理。抛开Android本身,我们对于事务的理解主要源于数据库,也就是一种批量性的操作,记录下你的操作集合,然后一次性处理,保证事务处理时候的安全性和高效性。FragmentManager看待事务的观点也基本一致,BackStackRecord的核心方法是addOp(Op):
void addOp(Op op) { if (mHead == null) { mHead = mTail = op; } else { op.prev = mTail; mTail.next = op; mTail = op; } op.enterAnim = mEnterAnim; op.exitAnim = mExitAnim; op.popEnterAnim = mPopEnterAnim; op.popExitAnim = mPopExitAnim; mNumOp++; }
我们看到,对于BackStackRecord对操作处理的组织是採用" 迭代器" 的模式,每个操作被记录成为Op对象,又能够当作" 备忘录" 模式来看待。而对于加入操作的入口:
public FragmentTransaction add(Fragment fragment, String tag) { doAddOp(0, fragment, tag, OP_ADD); return this; }public FragmentTransaction add(int containerViewId, Fragment fragment) { doAddOp(containerViewId, fragment, null, OP_ADD); return this; }public FragmentTransaction add(int containerViewId, Fragment fragment, String tag) { doAddOp(containerViewId, fragment, tag, OP_ADD); return this; }
是採用" Builder" 的方式来组织。
文章開始我已经提到了,Fragment的事务管理是比較出彩的代码,单纯的事务採用了至少三套模式来组织,并且组织起来丝毫没有感觉。
当然Fragment带给我们的惊喜还不仅限于此。我们总上面的代码片段能够看出,实际上,通过事务类BackStackRecord生成Op对象实际上在复制BackStackRecord的属性,所以当我们分析每个Op里面的数据的时候,能够直接用BackStackRecord中的属性映射。
int mNumOp; //Op数量 int mEnterAnim; //进入动画 int mExitAnim; //退出动画 int mPopEnterAnim; //弹出进入动画 int mPopExitAnim; //弹出退出动画 int mTransition; //转场动画 int mTransitionStyle; boolean mAddToBackStack; //是否增加到BackStack中
Op本身属于Command模式,它的Command列表各自是:
static final int OP_NULL = 0; static final int OP_ADD = 1; static final int OP_REPLACE = 2; static final int OP_REMOVE = 3; static final int OP_HIDE = 4; static final int OP_SHOW = 5; static final int OP_DETACH = 6; static final int OP_ATTACH = 7;
也许你也已经看出来了,没错,Op的属性就是作为Command的操作数。在BackStackRecord进行Commit了之后,BackStackRecord会将自己纳入FragmentManagerImpl的命令队列中处理。
每个处理单元用于处理各自的Op操作。
我们来看下代码:
BackStackRecord.java: int commitInternal(boolean allowStateLoss) { if (mCommitted) throw new IllegalStateException(" commit already called" ); mCommitted = true; if (mAddToBackStack) { mIndex = mManager.allocBackStackIndex(this); } else { mIndex = -1; } mManager.enqueueAction(this, allowStateLoss); return mIndex; }
BackStackRecord在提交的时候会将自己提交到mManager的Action队列中去。
而这样的Action队列的处理能够在随意线程中进行
FragmentManager.java: public void enqueueAction(Runnable action, boolean allowStateLoss) { if (!allowStateLoss) { checkStateLoss(); } synchronized (this) { if (mActivity == null) { throw new IllegalStateException(" Activity has been destroyed" ); } if (mPendingActions == null) { mPendingActions = new ArrayList< Runnable> (); } mPendingActions.add(action); if (mPendingActions.size() == 1) { mActivity.mHandler.removeCallbacks(mExecCommit); mActivity.mHandler.post(mExecCommit); } } }
我们看到实际上Action是被mExecCommit命令所运行,而它,将回调你所提交的BackStackRecord的run方法。
BackStackRecord.java: Op op = mHead; while (op != null) { ... }
我们看到,命令是以迭代器的方式在循环执行。
不同的命令将对Fragment有不同的状态变更操作,举个简单的样例:
Op.java:case OP_ADD: { Fragment f = op.fragment; f.mNextAnim = op.enterAnim; mManager.addFragment(f, false); } break;
当我们须要Add一个Fragment的时候,Op将调用FragmentManager的addFragment方法
FragmentManager.java: public void addFragment(Fragment fragment, boolean moveToStateNow) { if (mAdded == null) { mAdded = new ArrayList< Fragment> (); } makeActive(fragment); if (!fragment.mDetached) { if (mAdded.contains(fragment)) { throw new IllegalStateException(" Fragment already added: " + fragment); } mAdded.add(fragment); fragment.mAdded = true; fragment.mRemoving = false; if (fragment.mHasMenu & & fragment.mMenuVisible) { mNeedMenuInvalidate = true; } if (moveToStateNow) { moveToState(fragment); } } }
FragmentManager会将它先增加到自己的mAdded队列中去,然后通过调用moveToState方法来改变Fragment状态保证状态上的一致性。而这一部分,就是我们上一部分讲的内容,我们不再赘述。这样Fragment通过这样的优雅的方式就实现了事务的处理。
下一篇,我将给大家讲述Fragment关于Stack管理的部分源代码。
【[Android]Fragment源代码分析 事务】
推荐阅读
- WebService连接sql serever并使用Android端访问数据
- Gradle和Maven的对比和区别
- Mac的9款最佳密码管理器合集(哪个最好用())
- Windows的最佳时间跟踪软件合集(你最喜欢哪个())
- 10款最佳在线协作软件合集(哪个最适合你())
- 11款Windows的最佳PC清洁和优化软件合集
- 10款最佳PC Xbox 360模拟器合集(哪个最好用())
- 最佳在线照片打印服务有哪些(哪个最好?)
- 10大最佳个人理财服务软件合集(哪个最适合你())