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

本文出自: 【HansChen的博客】

概述

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

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

分析入口

  1. /**
  2. * 显示Fragment,假设Fragment已加入过,则直接show。否则构造一个Fragment
  3. *
  4. * @param containerViewId 容器控件id
  5. * @param clz Fragment类
  6. */
  7. protected void showFragment(@IdRes int containerViewId, Class<? extends Fragment> clz) {
  8. FragmentManager fm = getFragmentManager();
  9. FragmentTransaction ft = fm.beginTransaction();//開始事务管理
  10. Fragment f;
  11. if ((f = fm.findFragmentByTag(clz.getName())) == null) {
  12. try {
  13. f = clz.newInstance();
  14. ft.add(containerViewId, f, clz.getName());//加入操作
  15. } catch (Exception e) {
  16. e.printStackTrace();
  17. }
  18. } else {
  19. ft.show(f);//加入操作
  20. }
  21. ft.commit();//提交事务
  22. }

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

代码分析

FragmentManager



上图是获取FragmentManager的大体过程

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

  1. final FragmentController mFragments = FragmentController.createController(new HostCallbacks());
  2. /**
  3. * Return the FragmentManager for interacting with fragments associated
  4. * with this activity.
  5. */
  6. public FragmentManager getFragmentManager() {
  7. return mFragments.getFragmentManager();
  8. }

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

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

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

FragmentController构造方法

  1. private final FragmentHostCallback<?> mHost;
  2. private FragmentController(FragmentHostCallback<?
  3. > callbacks) {
  4. mHost = callbacks;
  5. }

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

FragmentController#getFragmentManager

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

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

FragmentHostCallback

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

FragmentHostCallback#getFragmentManagerImpl

  1. final FragmentManagerImpl mFragmentManager = new FragmentManagerImpl();
  2. FragmentManagerImpl getFragmentManagerImpl() {
  3. return mFragmentManager;
  4. }

最终找到FragmentManager的真身FragmentManagerImpl

FragmentManagerImpl#beginTransaction

  1. @Override
  2. public FragmentTransaction beginTransaction() {
  3. return new BackStackRecord(this);
  4. }

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

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

FragmentTransaction#add

  1. public FragmentTransaction add(int containerViewId, Fragment fragment, String tag) {
  2. doAddOp(containerViewId, fragment, tag, OP_ADD);
  3. return this;
  4. }
  5. private void doAddOp(int containerViewId, Fragment fragment, String tag, int opcmd) {
  6. //设置fragment的FragmentManagerImpl,mManager事实上就是Activity#HostCallbacks中的成员变量
  7. fragment.mFragmentManager = mManager;
  8. //设置fragment的tag
  9. if (tag != null) {
  10. if (fragment.mTag != null && !tag.equals(fragment.mTag)) {
  11. throw new IllegalStateException("...");
  12. }
  13. fragment.mTag = tag;
  14. }
  15. if (containerViewId != 0) {
  16. if (containerViewId == View.NO_ID) {
  17. throw new IllegalArgumentException("...");
  18. }
  19. if (fragment.mFragmentId != 0 && fragment.mFragmentId != containerViewId) {
  20. throw new IllegalStateException("");
  21. }
  22. //设置fragment的mContainerId以及mFragmentId
  23. fragment.mContainerId = fragment.mFragmentId = containerViewId;
  24. }
  25. //新增一个操作
  26. Op op = new Op();
  27. op.cmd = opcmd;
  28. op.fragment = fragment;
  29. //加入操作
  30. addOp(op);
  31. }
  32. //插入到链表的最后
  33. void addOp(Op op) {
  34. if (mHead == null) {
  35. mHead = mTail = op;
  36. } else {
  37. op.prev = mTail;
  38. mTail.next = op;
  39. mTail = op;
  40. }
  41. op.enterAnim = mEnterAnim;
  42. op.exitAnim = mExitAnim;
  43. op.popEnterAnim = mPopEnterAnim;
  44. op.popExitAnim = mPopExitAnim;
  45. mNumOp++;
  46. }

add的操作步骤为:

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

这里用到了一个类:

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

这是一个操作链表节点。

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

FragmentTransaction#commit

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

  1. public int commit() {
  2. return commitInternal(false);
  3. }
  4. int commitInternal(boolean allowStateLoss) {
  5. //防止反复commit
  6. if (mCommitted) {
  7. throw new IllegalStateException("commit already called");
  8. }
  9. //DEBUG代码统统无论
  10. if (FragmentManagerImpl.DEBUG) {
  11. Log.v(TAG, "Commit: " + this);
  12. LogWriter logw = new LogWriter(Log.VERBOSE, TAG);
  13. PrintWriter pw = new FastPrintWriter(logw, false, 1024);
  14. dump(" ", null, pw, null);
  15. pw.flush();
  16. }
  17. mCommitted = true;
  18. //仅仅有调用了addToBackStack方法之后,这个标记才会为true
  19. if (mAddToBackStack) {
  20. mIndex = mManager.allocBackStackIndex(this);
  21. } else {
  22. mIndex = -1;
  23. }
  24. //插入事物队列
  25. mManager.enqueueAction(this, allowStateLoss);
  26. return mIndex;
  27. }

FragmentManagerImpl#enqueueAction

  1. /**
  2. * Adds an action to the queue of pending actions.
  3. *
  4. * @param action the action to add
  5. * @param allowStateLoss whether to allow loss of state information
  6. * @throws IllegalStateException if the activity has been destroyed
  7. */
  8. public void enqueueAction(Runnable action, boolean allowStateLoss) {
  9. if (!allowStateLoss) {
  10. checkStateLoss();
  11. }
  12. synchronized (this) {
  13. if (mDestroyed || mHost == null) {
  14. throw new IllegalStateException("Activity has been destroyed");
  15. }
  16. if (mPendingActions == null) {
  17. mPendingActions = new ArrayList<Runnable>();
  18. }
  19. mPendingActions.add(action);
  20. if (mPendingActions.size() == 1) {
  21. mHost.getHandler().removeCallbacks(mExecCommit);
  22. mHost.getHandler().post(mExecCommit);
  23. }
  24. }
  25. }

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

  1. final Handler mHandler = new Handler();

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

  1. Runnable mExecCommit = new Runnable() {
  2. @Override
  3. public void run() {
  4. execPendingActions();
  5. }
  6. };
  7. /**
  8. * Only call from main thread!
  9. */
  10. public boolean execPendingActions() {
  11. if (mExecutingActions) {
  12. throw new IllegalStateException("Recursive entry to executePendingTransactions");
  13. }
  14. //再次检測是否主线程
  15. if (Looper.myLooper() != mHost.getHandler().getLooper()) {
  16. throw new IllegalStateException("Must be called from main thread of process");
  17. }
  18. boolean didSomething = false;
  19. while (true) {
  20. int numActions;
  21. synchronized (this) {
  22. //參数检測
  23. if (mPendingActions == null || mPendingActions.size() == 0) {
  24. break;
  25. }
  26. numActions = mPendingActions.size();
  27. if (mTmpActions == null || mTmpActions.length < numActions) {
  28. mTmpActions = new Runnable[numActions];
  29. }
  30. mPendingActions.toArray(mTmpActions);
  31. mPendingActions.clear();
  32. mHost.getHandler().removeCallbacks(mExecCommit);
  33. }
  34. mExecutingActions = true;
  35. //遍历运行待处理的事务操作
  36. for (int i=0; i<numActions; i++) {
  37. mTmpActions[i].run();
  38. mTmpActions[i] = null;
  39. }
  40. mExecutingActions = false;
  41. didSomething = true;
  42. }
  43. doPendingDeferredStart();
  44. return didSomething;
  45. }

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

  1. final class BackStackRecord extends FragmentTransaction implements
  2. FragmentManager.BackStackEntry, Runnable {
  3. static final String TAG = FragmentManagerImpl.TAG;
  4. ... ...
  5. }

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

BackStackRecord#run

  1. public void run() {
  2. ......
  3. if (mManager.mCurState >= Fragment.CREATED) {
  4. SparseArray<Fragment> firstOutFragments = new SparseArray<Fragment>();
  5. SparseArray<Fragment> lastInFragments = new SparseArray<Fragment>();
  6. calculateFragments(firstOutFragments, lastInFragments);
  7. beginTransition(firstOutFragments, lastInFragments, false);
  8. }
  9. //遍历链表。依据cmd事务类型依次处理事务
  10. Op op = mHead;
  11. while (op != null) {
  12. switch (op.cmd) {
  13. case OP_ADD: {
  14. Fragment f = op.fragment;
  15. f.mNextAnim = op.enterAnim;
  16. mManager.addFragment(f, false);
  17. }
  18. break;
  19. case OP_REPLACE: {
  20. Fragment f = op.fragment;
  21. int containerId = f.mContainerId;
  22. if (mManager.mAdded != null) {
  23. for (int i = mManager.mAdded.size() - 1; i >= 0; i--) {
  24. Fragment old = mManager.mAdded.get(i);
  25. if (old.mContainerId == containerId) {
  26. if (old == f) {
  27. op.fragment = f = null;
  28. } else {
  29. if (op.removed == null) {
  30. op.removed = new ArrayList<Fragment>();
  31. }
  32. op.removed.add(old);
  33. old.mNextAnim = op.exitAnim;
  34. if (mAddToBackStack) {
  35. old.mBackStackNesting += 1;
  36. }
  37. mManager.removeFragment(old, mTransition, mTransitionStyle);
  38. }
  39. }
  40. }
  41. }
  42. if (f != null) {
  43. f.mNextAnim = op.enterAnim;
  44. mManager.addFragment(f, false);
  45. }
  46. }
  47. break;
  48. case OP_REMOVE: {
  49. Fragment f = op.fragment;
  50. f.mNextAnim = op.exitAnim;
  51. mManager.removeFragment(f, mTransition, mTransitionStyle);
  52. }
  53. break;
  54. case OP_HIDE: {
  55. Fragment f = op.fragment;
  56. f.mNextAnim = op.exitAnim;
  57. mManager.hideFragment(f, mTransition, mTransitionStyle);
  58. }
  59. break;
  60. case OP_SHOW: {
  61. Fragment f = op.fragment;
  62. f.mNextAnim = op.enterAnim;
  63. mManager.showFragment(f, mTransition, mTransitionStyle);
  64. }
  65. break;
  66. case OP_DETACH: {
  67. Fragment f = op.fragment;
  68. f.mNextAnim = op.exitAnim;
  69. mManager.detachFragment(f, mTransition, mTransitionStyle);
  70. }
  71. break;
  72. case OP_ATTACH: {
  73. Fragment f = op.fragment;
  74. f.mNextAnim = op.enterAnim;
  75. mManager.attachFragment(f, mTransition, mTransitionStyle);
  76. }
  77. break;
  78. default: {
  79. throw new IllegalArgumentException("Unknown cmd: " + op.cmd);
  80. }
  81. }
  82. op = op.next;
  83. }
  84. mManager.moveToState(mManager.mCurState, mTransition,
  85. mTransitionStyle, true);
  86. if (mAddToBackStack) {
  87. mManager.addBackStackState(this);
  88. }
  89. }

到这一步,提交的事务就被真正运行了,我们知道。即使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. H+后台主题UI框架---整理

    本篇文章是对H+这种框架进行整理,顺便了解一下标准的代码规范的写法. 一.表单: 1).下面是一个基本表单: 现在来看这个表单的结构: 1.整个表单的外框结构是一个div,至于padding和marg ...

  2. shell学习四十九天----进程建立

    进程 前言:进程指的是运行中程序的一个实例.新进程由fork()与execve()等系统调用所起始,然后运行,知道他们下达exit()系统调用为止. linux系统都支持多进程.尽管计算机看起来像是一 ...

  3. POJ 2533 Longest Ordered Subsequence(dp LIS)

    Language: Default Longest Ordered Subsequence Time Limit: 2000MS   Memory Limit: 65536K Total Submis ...

  4. BZOJ 3671 NOI 2014 随机数生成器 贪心

    题目大意:实在是太难说明了,自己看pdf吧.. 思路:优先依照它说明的方法处理数组,然后为了让数列中尽可能多的出现小的数字,所以1是必需要出现的,这样才干使整个数列的排序后字典序最小. 我们思考,假设 ...

  5. amaze ui和bootstrap有哪些差别?

    amaze ui和bootstrap有哪些差别? 问题 我最近在学amaze ui,感觉如果单从功能性来看和bootstrap最大差别也就是扁平化,不过妹子ui号称对国产本土化支持更好,这个具体表现在 ...

  6. vue --- watch 高级用法

    假设有如下代码: <div> <p>FullName: {{fullName}}</p> <p>FirstName: <input type=&q ...

  7. 56.lambda表达式与绑定以及伪函数和绑定

    #include <iostream> #include <functional> using namespace std; using namespace std::plac ...

  8. groups---输出指定用户所在组的组成员,

    groups命令   groups命令在标准输入输出上输出指定用户所在组的组成员,每个用户属于/etc/passwd中指定的一个组和在/etc/group中指定的其他组. 语法 groups(选项)( ...

  9. Python线程池任务

    #!/usr/bin/env python # -*- coding:utf-8 -*- from concurrent.futures import ThreadPoolExecutor #线程池, ...

  10. Webservice银行报文接口设计

      Preface: 合理的软件架构设计其好处是不言而喻的,系统具有清晰的软件结构,良好的可扩展性,类的职能单一明确,系统的复杂度底.此前的一个实际项目中总结了些关于OO设计的实际应用,主要是围绕'高 ...