位置: 编程技术 - 正文

源码分析Fragmentd的BackStack管理过程(源码分析工具)

编辑:rootadmin

推荐整理分享源码分析Fragmentd的BackStack管理过程(源码分析工具),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:源码分析工具,源码分析工具,源码分析是什么意思,源码分析 nandflash verilog,源码分析 nandflash verilog,源码分析 nandflash verilog,源码分析jquery,源码分析怎么写,内容如对您有帮助,希望把文章链接给更多的朋友!

转载: Fragment基本用法

为了管理Activity中的fragments,需要调用Activity中的getFragmentManager()方法。因为FragmentManager的API是在Android 3.0,也即API level 开始引入的,所以对于之前的版本,需要使用support library v4中的FragmentActivity,并且使用getSupportFragmentManager()方法。用FragmentManager可以做的工作有:得到Activity中存在的fragment:  使用findFragmentById()或findFragmentByTag()方法。  将fragment弹出back stack:popBackStack(): 将back stack中最后一次的fragment转换弹出。如果没有可以出栈的东西,返回false。 这个函数是异步的:它将弹出栈的请求加入队列,但是这个动作直到应用回到事件循环才会执行。为back stack加上监听器:  addOnBackStackChangedListener()使用Fragment时,可以执行一些动作,比如增加、移除、替换等。所有这些改变构成一个集合,这个集合被叫做一个transaction。可以调用FragmentTransaction中的方法来处理这个transaction.以这样得到FragmentTransaction类的实例: [java] view plaincopyFragmentManager fragmentManager = getFragmentManager(); FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

每个transaction是一组同时执行的变化的集合。用add(), remove(), replace()方法,把所有需要的变化加进去,然后调用commit()方法,将这些变化应用。在commit()方法之前,你可以调用addToBackStack(),把这个transaction加入back stack中去,这个back stack是由activity管理的,当用户按返回键时,就会回到上一个fragment的状态。下面的代码非常典型,用一个新的fragment取代之前的fragment,并且将之前的状态存储在back stack中。

[java] view plaincopy// Create new fragment and transaction Fragment newFragment = new ExampleFragment(); FragmentTransaction transaction = getFragmentManager().beginTransaction(); // Replace whatever is in the fragment_container view with this fragment, // and add the transaction to the back stack transaction.replace(R.id.fragment_container, newFragment); transaction.addToBackStack(null); // Commit the transaction transaction.commit(); 通过调用addToBackStack(),commit()的一系列转换作为一个transaction被存储在back stack中,用户按Back键可以返回上一个转换前的状态。调用commit()方法并不能立即执行transaction中包含的改变动作,commit()方法把transaction加入activity的UI线程队列中。

下面我们对上述代码中出现的函数进行分析,以此来逐步学习Fragment的管理机制。

getSupportFragmentManager():

[java] view plaincopypublic FragmentManager getSupportFragmentManager() { return mFragments; } 该函数返回类型是FragmentManager,FragmentManager是一个抽象类,其实现类是FragmentManager.FragmentManagerImpl源码分析Fragmentd的BackStack管理过程(源码分析工具)

beginTransaction():该函数在FragmentManagerIMpl中的源码如下:

[java] view plaincopypublic FragmentTransaction beginTransaction() { return new BackStackRecord(this); } 返回一个BackStackRecord对象,该对象是FragmentTranscation的一个子类。BackStackRecord的声明如下:[java] view plaincopyfinal class BackStackRecord extends FragmentTransaction implements FragmentManager.BackStackEntry, Runnable {...} 该类实现了一个重要的接口:FragmentManager.BackStackEntry, 该接口代表了fragment back stack的一个入口。可以用FragmentManager.getBackStackEntry()来检索BackStackEntry。 接下来执行transaction.replace(), 查看BackStackRecord,调用过程源码如下:[java] view plaincopypublic FragmentTransaction replace(int containerViewId, Fragment fragment) { return replace(containerViewId, fragment, null); } public FragmentTransaction replace(int containerViewId, Fragment fragment, String tag) { if (containerViewId == 0) { throw new IllegalArgumentException("Must use non-zero containerViewId"); } doAddOp(containerViewId, fragment, tag, OP_REPLACE); return this; } 我们发现,replace()最终调用的函数为doAddOp(int containerViewId, Fragment fragment, String tag, int opcmd), 将Fragment和对Fragment所进行的操作放到op链表中:[java] view plaincopyprivate void doAddOp(int containerViewId, Fragment fragment, String tag, int opcmd) { fragment.mFragmentManager = mManager; if (tag != null) { if (fragment.mTag != null && !tag.equals(fragment.mTag)) { throw new IllegalStateException("Can't change tag of fragment " &#; fragment &#; ": was " &#; fragment.mTag &#; " now " &#; tag); } fragment.mTag = tag; } if (containerViewId != 0) { if (fragment.mFragmentId != 0 && fragment.mFragmentId != containerViewId) { throw new IllegalStateException("Can't change container ID of fragment " &#; fragment &#; ": was " &#; fragment.mFragmentId &#; " now " &#; containerViewId); } fragment.mContainerId = fragment.mFragmentId = containerViewId; } Op op = new Op(); op.cmd = opcmd; op.fragment = fragment; addOp(op); } 该函数首先设置fragment的mFragmentManager属性,然后再设置其mContainerId和mFragmentId,最后创建Op对象,然设置相应自段,其中cmd自动用来标识事务的类型,分为如下几类: 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()类是BackStackRecord中声明的结构体,本质上是一个双向链表的Node。addOp()如下:[java] view plaincopyvoid 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&#;&#;; } 该函数将Op对象添加到链表的末尾,并将mNumOp的&#;增一。

transaction.addToBackStack(null)设置了mAddToBackStack为true,源码如下:

[java] view plaincopypublic FragmentTransaction addToBackStack(String name) { if (!mAllowAddToBackStack) { throw new IllegalStateException( "This FragmentTransaction is not allowed to be added to the back stack."); } mAddToBackStack = true; mName = name; return this; } 此函数将mAddToBackStack自段设置为true,并设置mName字段。最后调用transaction.commit()来执行transaction。commit()的调用过程代码如下:[java] view plaincopypublic int commit() { return commitInternal(false); } 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); } mCommitted = true; if (mAddToBackStack) { mIndex = mManager.allocBackStackIndex(this); } else { mIndex = -1; } mManager.enqueueAction(this, allowStateLoss); return mIndex; } 由于mAddToBackStack为true,所以会用FragmentManager为BackstackRecorder也即FragmentTransaction分配一个index,分配过程如下:[java] view plaincopypublic int allocBackStackIndex(BackStackRecord bse) { synchronized (this) { if (mAvailBackStackIndices == null || mAvailBackStackIndices.size() <= 0) { if (mBackStackIndices == null) { mBackStackIndices = new ArrayList<BackStackRecord>(); } int index = mBackStackIndices.size(); if (DEBUG) Log.v(TAG, "Setting back stack index " &#; index &#; " to " &#; bse); mBackStackIndices.add(bse); return index; } else { int index = mAvailBackStackIndices.remove(mAvailBackStackIndices.size()-1); if (DEBUG) Log.v(TAG, "Adding back stack index " &#; index &#; " with " &#; bse); mBackStackIndices.set(index, bse); return index; } } } FragmentManager用mAvailBackStackIndices和mBackStackIndices两个数组来为BackStackRecord分配Index。mAvailBackStackIndices用来存储在mBackStackIndices中能够分配的Index,mBackStackIndices则用来保存BackStackRecord。这利用两个数组可以减少对mBackStackIndices的动态分配大小的次数,是一个以空间换时间的策略。上面的代码首先判断是否有可用的Index分配给BackStackRecord,若无则直接将BackStackRecord插入到mBackStackIndices;若存在的话则从mAvailBackStackIndices的队尾取出一个index,然后设置mBackStackIndices中该index下的&#;。让我们回到commit()中,该函数最后执行mManager.enqueAction(),源码如下:[html] view plaincopypublic void enqueueAction(Runnable action, boolean allowStateLoss) { if (!allowStateLoss) { checkStateLoss(); } synchronized (this) { if (mDestroyed || 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); } } } [java] view plaincopy该函数首先进行状态监测,查看该Fagment所在的Activity的生命周期是否处于Saving Activity之前,因为Activity保存状态往往是由用户离开那个Activity所造成的,在此之后执行commit会丢失一些状态信息。针对这种情况,可以使用commitAllowingStateLoss().最后将BackStackRecord加入到执行队列中。当第一次往执行 队列中添加消息时,首先会从消息队列中所有callback属性为mExecCommit的消息删除,然后重新将mExecCommit添加到消息队列。mExecCommit的定义如下: [java] view plaincopyRunnable mExecCommit = new Runnable() { @Override public void run() { execPendingActions(); } }; execPendingActions()只能在主线程内被调用,其内部通过一个循环对mPendingActions中的Actions进行执行。&#;得注意的是,每执行一次循环,mPendingActions中的所有Action都会被添加到一个临时数组中,然后这个数组被变量一遍以执行数组中的每个Runnable。同时,每个Runnable直接被调用了run,而不是开个线程执行的。当这个Runnable在执行的时候,mPendingActions数组可能会被添加内容。当某一时刻mPendingActions中的内容为空,则while循环退出。此部分代码如下:[java] view plaincopypublic boolean execPendingActions() { if (mExecutingActions) { throw new IllegalStateException("Recursive entry to executePendingTransactions"); } if (Looper.myLooper() != mActivity.mHandler.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(); mActivity.mHandler.removeCallbacks(mExecCommit); } //一次性执行完数组中所有的Action mExecutingActions = true; for (int i=0; i<numActions; i&#;&#;) { mTmpActions[i].run(); mTmpActions[i] = null; } mExecutingActions = false; didSomething = true; } if (mHavePendingDeferredStart) { boolean loadersRunning = false; for (int i=0; i<mActive.size(); i&#;&#;) { Fragment f = mActive.get(i); if (f != null && f.mLoaderManager != null) { loadersRunning |= f.mLoaderManager.hasRunningLoaders(); } } if (!loadersRunning) { mHavePendingDeferredStart = false; startPendingDeferredFragments(); } } return didSomething; } 由于BackstackRecorder实现了Runnable,我们来看看BackStackRecorder中的run(),如下所示:[java] view plaincopypublic void run() { if (FragmentManagerImpl.DEBUG) Log.v(TAG, "Run: " &#; this); if (mAddToBackStack) { if (mIndex < 0) { throw new IllegalStateException("addToBackStack() called after commit()"); } } bumpBackStackNesting(1); Op op = mHead; //遍历op,根据cmd的类型对Fragment和FragmentManager进行相应的设置 while (op != null) { switch (op.cmd) { case OP_ADD: { Fragment f = op.fragment; f.mNextAnim = op.enterAnim; //将Fragment添加到FragmentManager中,其源码显示是将Fragment添加到FragmentManager中的mActive数组中,并将Fragment添加到了数组mAdded中。 mManager.addFragment(f, false); } break; case OP_REPLACE: { Fragment f = op.fragment; if (mManager.mAdded != null) { //遍历已经添加的Fragment, for (int i=0; i<mManager.mAdded.size(); i&#;&#;) { Fragment old = mManager.mAdded.get(i); if (FragmentManagerImpl.DEBUG) Log.v(TAG, "OP_REPLACE: adding=" &#; f &#; " old=" &#; old); //如果发现两个mContainerId一样,则进行特殊处理 if (f == null || old.mContainerId == f.mContainerId) { if (old == f) { //两个Fragment一样,则置空,保留old中的Fragment op.fragment = f = null; } else { // 将old fragment加入到 op.removed数组中,保留op中的Fragment if (op.removed == null) { op.removed = new ArrayList<Fragment>(); } op.removed.add(old); old.mNextAnim = op.exitAnim; if (mAddToBackStack) { //设置old Fragment在BackStack中的Number old.mBackStackNesting &#;= 1; if (FragmentManagerImpl.DEBUG) Log.v(TAG, "Bump nesting of " &#; old &#; " to " &#; old.mBackStackNesting); } //对old Fragment设置相应的状态属性,如mAdded、mRemoving, 从FragmentManager中移除oldFrgment的相关属性 mManager.removeFragment(old, mTransition, mTransitionStyle); } } } } //将Fragment添加到FragmentManager中 if (f != null) { f.mNextAnim = op.enterAnim; mManager.addFragment(f, false); } } break; case OP_REMOVE: ...... } op = op.next; } //设置Fragment的当前状态,然后根据当前状态来回调Fragment的生命周期中的相关函数。此函数控制了Fragment的生命周期和Fragment的绘制,想要彻底理解Fragment的生命周期的同学可以认真研究此函数。 mManager.moveToState(mManager.mCurState, mTransition, mTransitionStyle, true); //将BackStackRecord加入到BackStack中,并回调onBackStackChanged if (mAddToBackStack) { mManager.addBackStackState(this); } } addBackStackState()的源码如下:[java] view plaincopyvoid addBackStackState(BackStackRecord state) { if (mBackStack == null) { mBackStack = new ArrayList<BackStackRecord>(); } mBackStack.add(state); //回调onBackStackChanged reportBackStackChanged(); } 可以看到传说中的BackStack就是在这里被创建的, FragmentManager中的BackStack主要是用来存储FragmentTransaction的。

小结:

FragmentTransaction中的Op链用来保存add、remove、replace等action,在FragmentTransaction的run执行时,Op链会被变量以调整每个节点的内容。

FragmentManager使用一个BackStack来管理FragmentTransaction;使用mAdded数组来添加被add的Fragment,Fragment的创建、显示等行为都受FragmentManager的控制。FragmentManager中的moveToState()是一个非常重要的函数,在FragmentTransaction run的时候被调用。下次我们将深入这个函数。

RecyclerView基本使用 RecyclerView是android5.0推出的新的控件,官方给出的说明是:RecyclerViewisamoreadvancedandflexibleversionofListView.Thiswidgetisacontainerforlargesetsofviewsthatcanberecycledandscrolle

Android 4.1.2系统添加重启功能 转自:

Android设计模式之单例模式 Singleton 一.概述单例模式是设计模式中最简单的一种,但是它没有设计模式中的那种各种对象之间的抽象关系,所以有人不认为它是一种模式,而是一种实现技巧.单

标签: 源码分析工具

本文链接地址:https://www.jiuchutong.com/biancheng/379572.html 转载请保留说明!

上一篇:Android开源项目第一篇——个性化控件(View)篇 收藏的(安卓app开源项目)

下一篇:RecyclerView基本使用(recycleview使用)

  • 农业企业免哪些税款
  • 建筑企业差额征税如何开票
  • 借款合同印花税最新政策2023年
  • 个税免税收入怎么进行更正申报
  • 2021小规模免税
  • 长期负债营运资金比率公式
  • 怎么算应纳税收多少
  • 建筑业企业分包出克的是否能上报
  • 个贷系统平账户
  • 公司借股东钱支付的利息如何做账?
  • 库存生产用钢材属于什么会计科目类别
  • 事业单位收到增值税专用发票抵扣联怎么办
  • 外地预缴企业所得税汇算清缴退税
  • 增值税专用发票电子版
  • 金税盘怎么开红字发票流程
  • 售楼部购买空调计入哪个科目
  • 附加税增值税免抵税额的数据从哪里提取的
  • 增值税进项销项怎么算
  • 税法种类及税率
  • 灭火器属于办公设施吗
  • 委外开发费用可以加计扣除吗
  • 房地产企业申请破产,原来的购房合同还有效吗?
  • windows10如何设置屏幕常亮
  • 转让二手宾馆需要注意事项
  • 财政拨付专项资金进什么会计科目
  • 应交增值税的会计科目
  • linux cls命令
  • fpzs1是什么文件可以删除吗
  • modelist模型
  • 总分类账户原材料
  • 商品流通企业库存商品的核算方法主要有
  • laravel artisan命令
  • html中的标签有哪些
  • 低值易耗品摊销表格
  • python 构建
  • 退质保金计入什么科目
  • 其他发票是什么意思
  • 收款收据可以盖业务章吗
  • java 读写锁 map
  • mysql的一些命令
  • 欠对方钱对方公司已注销
  • 工会经费上缴流程
  • 委外加工怎么盘点
  • 怎么定义一个注解
  • 外经证办好了后怎么开票
  • 税务登记证证书编号是什么
  • 个人扣税是怎么扣的
  • 哪些合同不用计提印花税
  • 跨区域预缴税款流程
  • 什么是试算平衡表,编制试算平衡表时应注意哪些方面
  • 错账更正方法有几种分别适用于什么情况
  • 固定资产置换存货
  • 公司车过户给个人多久不用补税
  • 农产品收购进项税抵扣会计分录
  • 企业贷款利息多少
  • 给业务员的佣金怎么做账
  • 职工薪酬包括的内容
  • 资产负债表和利润表的利润不一致
  • 购入土地使用权以什么为计税依据
  • 期间费用率怎么算
  • 建筑企业人工费计入什么科目
  • MySQL 5.6 中 TIMESTAMP 的变化分析
  • ubuntu18虚拟机
  • oracle linux6.9
  • helpcfg是什么文件
  • SSDP Discovery Service 是什么可以禁用吗
  • 老毛桃U盘启动盘工具安装Win8的详细图文教程
  • xp系统的程序和功能在哪里
  • windowsxp优化教程
  • XP IIS5.1 + PHP 5.2.1 + MySQL 5.0.37 + Zend 3.2.6 + phpMyAdmin-2.10.0.2环境配置
  • winxp内存不能为read
  • windows visual studio openGL开发环境配置
  • js怎么用jquery
  • 利用Python中的turtle绘制乡村振兴
  • 广东省电子职业技术学院
  • 纳税申报逾期怎样补报?
  • 车辆购置税税率多少
  • 河南旧县为什么叫新县
  • 关于新时代新征程
  • 国税和地税的税种有哪些
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设