转载请标明出处:http://blog.csdn.net/shensky711/article/details/53132952

本文出自: 【HansChen的博客】

概述

在Fragment使用中,有时候须要对Fragment进行addremoveshowhidereplace等操作来进行Fragment的显示隐藏等管理。这些管理是通过FragmentTransaction进行事务管理的。事务管理是对于一系列操作进行管理,一个事务包括一个或多个操作命令,是逻辑管理的工作单元。

一个事务開始于第一次运行操作语句,结束于Commit。通俗地将。就是把多个操作缓存起来,等调用commit的时候,统一批处理。以下会对Fragmeng的事务管理做一个代码分析

分析入口

    /**
* 显示Fragment,假设Fragment已加入过,则直接show。否则构造一个Fragment
*
* @param containerViewId 容器控件id
* @param clz Fragment类
*/
protected void showFragment(@IdRes int containerViewId, Class<? extends Fragment> clz) {
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();//開始事务管理
Fragment f;
if ((f = fm.findFragmentByTag(clz.getName())) == null) {
try {
f = clz.newInstance();
ft.add(containerViewId, f, clz.getName());//加入操作
} catch (Exception e) {
e.printStackTrace();
}
} else {
ft.show(f);//加入操作
}
ft.commit();//提交事务
}

上面是一个简单的显示Fragment的栗子,简单推断一下Fragment是否已加入过,加入过就直接show,否则构造一个Fragment,最后提交事务。

代码分析

FragmentManager



上图是获取FragmentManager的大体过程

要管理Fragment事务。首先是须要拿到FragmentManager。在Activity中能够通过getFragmentManager()方法获取(使用兼容包的话。通过FragmentActivity#getSupportFragmentManager())。在这里我们就不正确兼容包进行分析了

    final FragmentController mFragments = FragmentController.createController(new HostCallbacks());

    /**
* Return the FragmentManager for interacting with fragments associated
* with this activity.
*/
public FragmentManager getFragmentManager() {
return mFragments.getFragmentManager();
}

FragmentManager是一个抽象类。它是通过mFragments.getFragmentManager()来获取的。mFragments是FragmentController对象,它通过FragmentController.createController(new HostCallbacks())生成,这是一个静态工厂方法:

    public static final FragmentController createController(FragmentHostCallback<?> callbacks) {
return new FragmentController(callbacks);
}

在这里面直接new了一个FragmentController对象,注意FragmentController的构造方法须要传入一个FragmentHostCallback

FragmentController构造方法

    private final FragmentHostCallback<?> mHost;
private FragmentController(FragmentHostCallback<? > callbacks) {
mHost = callbacks;
}

构造方法非常easy,传入了一个FragmentHostCallback实例

FragmentController#getFragmentManager

    public FragmentManager getFragmentManager() {
return mHost.getFragmentManagerImpl();
}

这里又调用了mHost的getFragmentManagerImpl方法。希望童鞋们没有被绕晕,mHost是一个FragmentHostCallback实例。那我们回过头来看看它传进来的地方

FragmentHostCallback

这个FragmentHostCallback是一个抽象类,我们能够看到,在Activity中是传入了 Activity#HostCallbacks内部类,这个就是FragmentHostCallback的实现类

FragmentHostCallback#getFragmentManagerImpl

    final FragmentManagerImpl mFragmentManager = new FragmentManagerImpl();
FragmentManagerImpl getFragmentManagerImpl() {
return mFragmentManager;
}

最终找到FragmentManager的真身FragmentManagerImpl

FragmentManagerImpl#beginTransaction

    @Override
public FragmentTransaction beginTransaction() {
return new BackStackRecord(this);
}

能够看到,所谓的FragmentTransaction事实上就是一个BackStackRecord。到如今。FragmentManager和FragmentTransaction我们都找到了。下图就是各个类之间的关系:

以下開始真正的事务管理分析,我们先选择一个事务add来进行分析

FragmentTransaction#add

    public FragmentTransaction add(int containerViewId, Fragment fragment, String tag) {
doAddOp(containerViewId, fragment, tag, OP_ADD);
return this;
} private void doAddOp(int containerViewId, Fragment fragment, String tag, int opcmd) { //设置fragment的FragmentManagerImpl,mManager事实上就是Activity#HostCallbacks中的成员变量
fragment.mFragmentManager = mManager; //设置fragment的tag
if (tag != null) {
if (fragment.mTag != null && !tag.equals(fragment.mTag)) {
throw new IllegalStateException("...");
}
fragment.mTag = tag;
} if (containerViewId != 0) {
if (containerViewId == View.NO_ID) {
throw new IllegalArgumentException("...");
}
if (fragment.mFragmentId != 0 && fragment.mFragmentId != containerViewId) {
throw new IllegalStateException("");
}
//设置fragment的mContainerId以及mFragmentId
fragment.mContainerId = fragment.mFragmentId = containerViewId;
} //新增一个操作
Op op = new Op();
op.cmd = opcmd;
op.fragment = fragment;
//加入操作
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++;
}

add的操作步骤为:

  1. 设置fragment的FragmentManagerImpl
  2. 设置fragment的tag
  3. 设置fragment的mContainerId以及mFragmentId
  4. 插入一个类型为OP_ADD的操作到链表最后

这里用到了一个类:

    static final class Op {
Op next;//下一操作节点
Op prev;//上一操作节点
int cmd;//操作类型,可选有:OP_NULL|OP_ADD|OP_REPLACE|OP_REMOVE|OP_HIDE|OP_SHOW|OP_DETACH|OP_ATTACH
Fragment fragment;//操作的Fragment对象
int enterAnim;//入场动画
int exitAnim;//出场动画
int popEnterAnim;//弹入动画
int popExitAnim;//弹出动画
ArrayList<Fragment> removed;
}

这是一个操作链表节点。

全部add、remove、hide等事物最终会形成一个操作链

FragmentTransaction#commit

等全部操作都插入后,最后我们须要调用FragmentTransaction的commit方法。操作才会真正地运行。

    public int commit() {
return commitInternal(false);
} int commitInternal(boolean allowStateLoss) {
//防止反复commit
if (mCommitted) {
throw new IllegalStateException("commit already called");
} //DEBUG代码统统无论
if (FragmentManagerImpl.DEBUG) {
Log.v(TAG, "Commit: " + this);
LogWriter logw = new LogWriter(Log.VERBOSE, TAG);
PrintWriter pw = new FastPrintWriter(logw, false, 1024);
dump(" ", null, pw, null);
pw.flush();
} mCommitted = true; //仅仅有调用了addToBackStack方法之后,这个标记才会为true
if (mAddToBackStack) {
mIndex = mManager.allocBackStackIndex(this);
} else {
mIndex = -1;
}
//插入事物队列
mManager.enqueueAction(this, allowStateLoss);
return mIndex;
}

FragmentManagerImpl#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(Runnable 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<Runnable>();
}
mPendingActions.add(action);
if (mPendingActions.size() == 1) {
mHost.getHandler().removeCallbacks(mExecCommit);
mHost.getHandler().post(mExecCommit);
}
}
}

这里把操作加入到mPendingActions列表里去。并通过mHost.getHandler()获取Handler发送运行请求。从上面的分析知道。mHost就是Activity的HostCallbacks。构造方法中把Activity的mHandler传进去了,这里运行的mHost.getHandler()获取到的也就是Activity中的mHandler,这样做是由于须要在主线程中运行

final Handler mHandler = new Handler();

再看看mExecCommit中做了什么操作:

    Runnable mExecCommit = new Runnable() {
@Override
public void run() {
execPendingActions();
}
}; /**
* Only call from main thread!
*/
public boolean execPendingActions() {
if (mExecutingActions) {
throw new IllegalStateException("Recursive entry to executePendingTransactions");
} //再次检測是否主线程
if (Looper.myLooper() != mHost.getHandler().getLooper()) {
throw new IllegalStateException("Must be called from main thread of process");
} boolean didSomething = false; while (true) {
int numActions; synchronized (this) { //參数检測
if (mPendingActions == null || mPendingActions.size() == 0) {
break;
} numActions = mPendingActions.size();
if (mTmpActions == null || mTmpActions.length < numActions) {
mTmpActions = new Runnable[numActions];
} mPendingActions.toArray(mTmpActions);
mPendingActions.clear();
mHost.getHandler().removeCallbacks(mExecCommit);
} mExecutingActions = true;
//遍历运行待处理的事务操作
for (int i=0; i<numActions; i++) {
mTmpActions[i].run();
mTmpActions[i] = null;
}
mExecutingActions = false;
didSomething = true;
} doPendingDeferredStart(); return didSomething;
}

插入了事物之后,就是在主线程中把须要处理的事务统一处理。处理事务是通过运行mTmpActions[i].run()进行的,这个mTmpActions[i]就是前面我们通过enqueueAction方法插入的BackStackRecord,童鞋们可能没注意到,它但是一个Runnable,我们来看看它的定义

final class BackStackRecord extends FragmentTransaction implements
FragmentManager.BackStackEntry, Runnable {
static final String TAG = FragmentManagerImpl.TAG; ... ...
}

兜兜转转,我们又回到了BackStackRecord

BackStackRecord#run

    public void run() {

        ......

        if (mManager.mCurState >= Fragment.CREATED) {
SparseArray<Fragment> firstOutFragments = new SparseArray<Fragment>();
SparseArray<Fragment> lastInFragments = new SparseArray<Fragment>();
calculateFragments(firstOutFragments, lastInFragments);
beginTransition(firstOutFragments, lastInFragments, false);
}
//遍历链表。依据cmd事务类型依次处理事务
Op op = mHead;
while (op != null) {
switch (op.cmd) {
case OP_ADD: {
Fragment f = op.fragment;
f.mNextAnim = op.enterAnim;
mManager.addFragment(f, false);
}
break;
case OP_REPLACE: {
Fragment f = op.fragment;
int containerId = f.mContainerId;
if (mManager.mAdded != null) {
for (int i = mManager.mAdded.size() - 1; i >= 0; i--) {
Fragment old = mManager.mAdded.get(i);
if (old.mContainerId == containerId) {
if (old == f) {
op.fragment = f = null;
} else {
if (op.removed == null) {
op.removed = new ArrayList<Fragment>();
}
op.removed.add(old);
old.mNextAnim = op.exitAnim;
if (mAddToBackStack) {
old.mBackStackNesting += 1;
}
mManager.removeFragment(old, mTransition, mTransitionStyle);
}
}
}
}
if (f != null) {
f.mNextAnim = op.enterAnim;
mManager.addFragment(f, false);
}
}
break;
case OP_REMOVE: {
Fragment f = op.fragment;
f.mNextAnim = op.exitAnim;
mManager.removeFragment(f, mTransition, mTransitionStyle);
}
break;
case OP_HIDE: {
Fragment f = op.fragment;
f.mNextAnim = op.exitAnim;
mManager.hideFragment(f, mTransition, mTransitionStyle);
}
break;
case OP_SHOW: {
Fragment f = op.fragment;
f.mNextAnim = op.enterAnim;
mManager.showFragment(f, mTransition, mTransitionStyle);
}
break;
case OP_DETACH: {
Fragment f = op.fragment;
f.mNextAnim = op.exitAnim;
mManager.detachFragment(f, mTransition, mTransitionStyle);
}
break;
case OP_ATTACH: {
Fragment f = op.fragment;
f.mNextAnim = op.enterAnim;
mManager.attachFragment(f, mTransition, mTransitionStyle);
}
break;
default: {
throw new IllegalArgumentException("Unknown cmd: " + op.cmd);
}
} op = op.next;
} mManager.moveToState(mManager.mCurState, mTransition,
mTransitionStyle, true); if (mAddToBackStack) {
mManager.addBackStackState(this);
}
}

到这一步,提交的事务就被真正运行了,我们知道。即使commit了事务之后,也不是同步运行的,是通过Handler发送到主线程运行的。

全部事务的处理都是在run方法里面运行。但是我们留意到,想要搞清楚add、remove等事务背后真正做了什么。还须要深入了解FragmentManagerImpl。

本文主要解说Fragment事务的流程,FragmentManagerImpl的分析准备放到下一篇分析文章「Fragment源代码分析」中,相信通过分析之后,就能够对Fragment的生命周期也有一个非常好的认识了

Fragment事务管理源代码分析的更多相关文章

  1. Spring事务管理全面分析

    Spring 事务属性分析什么是事物  事务管理对于企业应用而言至关重要.它保证了用户的每一次操作都是可靠的,即便出现了异常的访问情况,也不至于破坏后台数据的完整性.就像银行的自助取款机,通常都能正常 ...

  2. [Android]Fragment源代码分析(三) 事务

    Fragment管理中,不得不谈到的就是它的事务管理,它的事务管理写的很的出彩.我们先引入一个简单经常使用的Fragment事务管理代码片段: FragmentTransaction ft = thi ...

  3. 全面分析 Spring 的编程式事务管理及声明式事务管理

    开始之前 关于本教程 本教程将深入讲解 Spring 简单而强大的事务管理功能,包括编程式事务和声明式事务.通过对本教程的学习,您将能够理解 Spring 事务管理的本质,并灵活运用之. 先决条件 本 ...

  4. 全面分析 Spring 的编程式事务管理及声明式事务管理--转

    开始之前 关于本教程 本教程将深入讲解 Spring 简单而强大的事务管理功能,包括编程式事务和声明式事务.通过对本教程的学习,您将能够理解 Spring 事务管理的本质,并灵活运用之. 先决条件 本 ...

  5. redis 源代码分析(一) 内存管理

    一,redis内存管理介绍 redis是一个基于内存的key-value的数据库,其内存管理是很重要的,为了屏蔽不同平台之间的差异,以及统计内存占用量等,redis对内存分配函数进行了一层封装,程序中 ...

  6. 【转】Spring事务管理

    原文链接 在 Spring 中,事务是通过 TransactionDefinition 接口来定义的.该接口包含与事务属性有关的方法.具体如清单 1 所示: 清单 1. TransactionDefi ...

  7. spring事务管理——编程式事务、声明式事务

    本教程将深入讲解 Spring 简单而强大的事务管理功能,包括编程式事务和声明式事务.通过对本教程的学习,您将能够理解 Spring 事务管理的本质,并灵活运用之. 先决条件 本教程假定您已经掌握了 ...

  8. Spring编程式事务管理及声明式事务管理

    本文将深入讲解 Spring 简单而强大的事务管理功能,包括编程式事务和声明式事务.通过对本教程的学习,您将能够理解 Spring 事务管理的本质,并灵活运用之. Spring 事务属性分析 事务管理 ...

  9. Spring 简单而强大的事务管理功能

    开始之前 关于本教程 本教程将深入讲解 Spring 简单而强大的事务管理功能,包括编程式事务和声明式事务.通过对本教程的学习,您将能够理解 Spring 事务管理的本质,并灵活运用之. 先决条件 本 ...

随机推荐

  1. SpringMVC与SpringBoot返回静态页面遇到的问题

    1.SpringMVC静态页面响应 package com.sv.controller; import org.springframework.stereotype.Controller; impor ...

  2. 最新华为数通HCNP-随堂培训视频课程 大牛讲解高清带实验

    2017年最新华为数通HCNP-随堂培训视频课程 大牛讲解高清带实验 2017最新的华为中级HCNP培训,数通方向,讲解非常牛高清课程附带实验. 华为数通HCNP-2017年最新随堂培训视频(高清)\ ...

  3. 实现IE下兼容CSS3的圆角效果

    有些CSS3的牛逼的效果在IE下展示不出来是最烦人的啦,在项目中做的圆角效果到了IE下一堆方块....忒尴尬了...,找了个替代解决方案 1.首先下载一个js插件PIE.js百度一搜都是的,我也就不写 ...

  4. Android 第三方分享中遇到的问题以及解决方案

    本文来自http://blog.csdn.net/liuxian13183/ ,引用必须注明出处! 第三方登录和分享过程中难免遇到各种纠结的问题,下面将我遇到的分享给大家. 先说第三方登录 1.首先要 ...

  5. php将数组或字符串写入文件

    //将数组保存在文件里 function export_to_file($file, $variable) { $fopen = fopen($file, 'wb'); if (!$fopen) { ...

  6. 聊聊高并发(十八)理解AtomicXXX.lazySet方法

    看过java.util.concurrent.atomic包里面各个AtomicXXX类实现的同学应该见过lazySet方法.比方AtomicBoolean类的lazySet方法 public fin ...

  7. 使用 Facebook开源动画库 POP 实现真实衰减动画

    1. POP动画基于底层刷新原理.是基于CADisplayLink,1秒钟运行60秒,接近于游戏开发引擎 @interface ViewController () @property (nonatom ...

  8. js函数的解析与执行过程

    function f(a,b,c){ alert(a);//函数字符串 alert(b); var b = 5; function a(){ } } f(1,2); //预处理 lexicalEnvi ...

  9. 商业模式(二):P2P网贷平台,利差和服务费为主的金融玩法

    2014~2015,先后在2家P2P平台工作过,还了解过其它若干武汉P2P平台. 结合自己的工作经历和理财经历,说几句~ 1.P2P网贷这种金融类的创业项目和经营风险,远高于制造业和服务业~      ...

  10. iOS开发--漫谈内存管理(一)

    1.MRC与ARC 苹果提供两种内存管理机制:一种是MRC(manual reference count),即手动引用计数:还有一种是ARC(auto reference count).即自己主动引用 ...