看到我们代码里面最经常用的fragment,总有一种冲动想去看看源码到底是怎么执行的,要不就写点关于fragment源码的文章吧。这几年安卓系统版本不断优化,fragment代码也有变化,写点自己的小小认知,先看看总体的调用代码
流程就是实例化一个事务对象,然后replace或者add,最后提交,大家可以带着几个问题往下看,transaction 事务内部是个啥,replace/add源码如何实现,为啥最后才是commitAllowingStateLoss()?这里的提交还有其他的方式commit,commitNow()和commitNowAllowingStateLoss(),有兴趣可以自己去了解
先看看第一步
其中getSupportFragmentManager()是在FragmentActivity里面,
1先看这个mFragments,他是FragmentController,它再调用的 getSupportFragmentManager()
2 3最后调用的就是返回一个FragmentManagerImpl
4 5 6其实这个最后可以看到,是实例化了一个回退栈BackStackRecord(关联的插播一句安卓源代码里面也有其他几个地方有用record,ActivityStack,TaskRecord,ActivityRecord,一样也是用ArrayList来管理),这个回退栈是继承 了FragmentTransaction,所以add/replace、commit等都在回退栈里实现,也就意味着他是支持事务操作的,而事务是可以回退的,所以这里的事务是由一个回退栈来实现,这是个比较重要的思想,接下来主要去BackStackRecord里面看实现,我们经常看到replace方法,查看它的调用链
7这里说明下,有个管理Op对象的也是用ArrayList来管理,也就是Op对象也有顺序关系,Op对象是个啥?是一个动画相关的辅助类,这个对象很重要,不仅切换fragment页面的时候用到,本身fragment也包含在其中了
从构造函数可知,这个切换动画辅助对类Op依赖了fragment和添加模式cmd,记录了到底是add还是replace。我们在代码里面调用replace或者add这个步骤的时候其实是在添加他的切换动画对象,所以对fragment的管理需要借助Op对象,从这个对象里面来获取fragment,再来看看add,其实也是跟replace一样的,都是最终调用到addOp函数,然后加到可变数组里面;先做个总结BackStackRecord类包含了Op类,Op类包含了fragment和添加模式cmd,之后的操作就是针对BackStackRecord做管理,然后获取Op,接着获取Fragment,而BackStackRecord是由FragmentManagerImpl的ArrayList<BackStackRecord> mBackStack来管理,它又是由Activity管理,这里就得出一个管理流程Activity->FragmentManagerImpl->BackStackRecord->Fragment,明白这个主线,才有办法理解整个生命周期,这个可以下次再分析。
接下来准备看看一个函数,commitAllowingStateLoss()提交函数,其实Fragment真正进入栈是在提交的时候,忙活了半天,前面的replace和add其实都是在做准备,这也体现了事务的特点,准备各种操作,最后一步提交才是真正执行。首先关注这里的前面两个函数,差别就是是否允许丢失状态,
内部最终调用commitInternal方法
这里看到一个变量mAddToBackStack,Fragment事务在目前的8.0以上系统是默认开启,本次只在8.0分析,还可以调用addToBackStack方法设置变量mAddToBackStack=true,由这个变量来控制分配栈索引。
allocBackStackIndex该方法用于给加入到返回栈的 BackStackRecord 分配 mIndex 下标,便于下次快速查找
前面我们说到commit和commitAllowingStateLoss的区别,是否丢失状态,其实就是判断是否抛出异常,判断你在onSaveInstanceState函数之前能不能调用,也就是做了个调用位置的限制。我们看看onSaveInstanceState函数在Activity里面是在onPause()->onSaveInstanceState->onStop(),意思简单说就是不能在Activity页面进入后台之后再调用,比如不能在onStop和onDestroy里面调用。这是因为当activity再次被恢复时commit之后的状态将丢失,如果丢失也没关系,那么使用commitAllowingStateLoss()方法,这个可以看看其他链接https://blog.csdn.net/dajian35/article/details/81368456
最后我们知道Fragment也是通过ArrayList来管理,因为不同系统版本的实现不一样,历史版本里面有用过双链表来实现,查找效率不如arraylist,这里猜测下谷歌可能还是希望切换或者恢复fragment的时候快点吧,毕竟数组的查找速度比链表快点,因为在很多新闻客户端动不动有十个八个的fragment滑动,链表每次都是从队头开始查找,而且链表是分散存储在MainMemory堆区,数组是连续存储在CPU缓存区,理论上性能就差了33倍,显然慢点。稍微说下add方法,它加入回退栈思路跟replace几乎一样,不同就是使用fragment在show()的时候每次界面是否回到初始状态,add加入方式是保留状态的,replace加入的方式是不保留状态的。这里插一句,栈可以用两种数据结构来表示,数组或者链表来表示,这里的回退栈用的是可变数组ArrayList来管理,我们伟大的JDK里面的Stack也是用数组来表示的,大家有空可以去看看源代码怎么实现的,所以你会发现大师们都在从数据结构开始优化代码,想想码农的核心能力其实除了算法还有数据结构这个说法没毛病,JDK里面的数据结构还真不少,学起来估计得掉不少头发........
网友评论