阿里P7Android高级架构进阶视频免费学习请点击:https://space.bilibili.com/474380680
本篇文章将先从以下三个内容来介绍Fragment管理与内核:
- [Fragment事务管理源码分析]
- [Fragment的自定义转场动画]
- [Fragment嵌套、getChildFragmentManager]
一、Fragment事务管理源码分析
1.1概述
在Fragment使用中,有时候需要对Fragment进行add、remove、show、hide、replace等操作来进行Fragment的显示隐藏等管理,这些管理是通过FragmentTransaction进行事务管理的。事务管理是对于一系列操作进行管理,一个事务包含一个或多个操作命令,是逻辑管理的工作单元。一个事务开始于第一次执行操作语句,结束于Commit。通俗地将,就是把多个操作缓存起来,等调用commit的时候,统一批处理。下面会对Fragmeng的事务管理做一个代码分析
1.2分析入口
上面是一个简单的显示Fragment的栗子,简单判断一下Fragment是否已添加过,添加过就直接show,否则构造一个Fragment,最后提交事务。
1.3代码分析
1.3.1FragmentManager
上图是获取FragmentManager的大体过程
要管理Fragment事务,首先是需要拿到FragmentManager,在Activity中可以通过getFragmentManager()方法获取(使用兼容包的话,通过FragmentActivity#getSupportFragmentManager()),在这里我们就不对兼容包进行分析了
FragmentManager是一个抽象类,它是通过mFragments.getFragmentManager()来获取的,mFragments是FragmentController对象,它通过FragmentController.createController(new HostCallbacks())生成,这是一个静态工厂方法:
在这里面直接new了一个FragmentController对象,注意FragmentController的构造方法需要传入一个FragmentHostCallback
1.3.2FragmentController构造方法
构造方法很简单,传入了一个FragmentHostCallback实例
1.3.3FragmentController#getFragmentManager
这里又调用了mHost的getFragmentManagerImpl方法,希望童鞋们没有被绕晕,mHost是一个FragmentHostCallback实例,那我们回过头来看看它传进来的地方
1.3.4FragmentHostCallback
这个FragmentHostCallback是一个抽象类,我们可以看到,在Activity中是传入了 Activity#HostCallbacks内部类,这个就是FragmentHostCallback的实现类
1.3.5FragmentHostCallback#getFragmentManagerImpl
终于找到FragmentManager的真身FragmentManagerImpl了
1.3.6FragmentManagerImpl#beginTransaction
可以看到,所谓的FragmentTransaction其实就是一个BackStackRecord。到现在,FragmentManager和FragmentTransaction我们都找到了。下图就是各个类之间的关系:
下面开始真正的事务管理分析,我们先选择一个事务add来进行分析
1.3.7FragmentTransaction#add
add的操作步骤为:
设置fragment的FragmentManagerImpl
设置fragment的tag
设置fragment的mContainerId以及mFragmentId
插入一个类型为OP_ADD的操作到链表最后
这里用到了一个类:
这是一个操作链表节点。所有add、remove、hide等事物最终会形成一个操作链
1.3.8FragmentTransaction#commit
等所有操作都插入后,最后我们需要调用FragmentTransaction的commit方法,操作才会真正地执行。
1.3.9FragmentManagerImpl#enqueueAction
这里把操作添加到mPendingActions列表里去。并通过mHost.getHandler()获取Handler发送执行请求。从上面的分析知道,mHost就是Activity的HostCallbacks,构造方法中把Activity的mHandler传进去了,这里执行的mHost.getHandler()获取到的也就是Activity中的mHandler,这样做是因为需要在主线程中执行
再看看mExecCommit中做了什么操作:
插入了事物之后,就是在主线程中把需要处理的事务统一处理,处理事务是通过执行mTmpActions[i].run()进行的,这个mTmpActions[i]就是前面我们通过enqueueAction方法插入的BackStackRecord,童鞋们可能没注意到,它可是一个Runnable,我们来看看它的定义
兜兜转转,我们又回到了BackStackRecord
1.3.10BackStackRecord#run
到这一步,提交的事务就被真正执行了,我们知道,即使commit了事务之后,也不是同步执行的,是通过Handler发送到主线程执行的。
所有事务的处理都是在run方法里面执行,但是我们留意到,想要搞清楚add、remove等事务背后真正做了什么,还需要深入了解FragmentManagerImpl。
二、Fragment转场动画
Fragment的转场动画实现分为使用v4包和不使用v4包两种情况,不使用v4包的话,最低API Level需要是11。
2.1标准转场动画:
可以给Fragment指定标准的转场动画,通过setTransition(int transit)方法。
该方法可传入的三个参数是:
TRANSIT_NONE,
TRANSIT_FRAGMENT_OPEN,
TRANSIT_FRAGMENT_CLOSE
分别对应无动画、打开形式的动画和关闭形式的动画。
标准动画设置好后,在Fragment添加和移除的时候都会有。
2.2自定义转场动画
自定义转场动画是通过setCustomAnimations()方法,因为Fragment添加时可以指定加入到Back Stack中,所以转场动画有添加、移除、从Back stack中pop出来,还有进入四种情况。
注意setCustomAnimations()方法必须在add、remove、replace调用之前被设置,否则不起作用。
2.3 android.app.Fragment
类参考:
Fragment:http://developer.android.com/reference/android/app/Fragment.html
FragmentTransaction:http://developer.android.com/reference/android/app/FragmentTransaction.html
不使用v4包的情况下(min API >=11)所对应的动画类型是Property Animation。
即动画资源文件需要放在resanimator*目录下,且根标签是<set>, <objectAnimator>, or <valueAnimator>*三者之一。
这一点也可以从Fragment中的这个方法看出:onCreateAnimator(int transit, boolean enter, int nextAnim),返回值是Animator。
自定义转场动画时,四个参数的形式setCustomAnimations (int enter, int exit, int popEnter, int popExit)是API Level 13才有的,11只引入了两个动画的形式,即无法指定Back Stack栈操作时的转场动画。
代码例子:
其中四个动画是从ApiDemos中拿来的:
fragment_slide_left_enter:
fragment_slide_left_exit:
fragment_slide_right_enter:
fragment_slide_right_exit:
android.support.v4.app.Fragment
Fragment:http://developer.android.com/reference/android/support/v4/app/Fragment.html
FragmentTransaction:http://developer.android.com/reference/android/support/v4/app/FragmentTransaction.html
使用v4包,Fragment的使用不再局限于API Level 11之上,低等级的API也可以使用,但是这时候转场动画的类型是View Animation。
动画资源放在*resanim*路径下,和Activity的转场动画一样。
Fragment中的方法:onCreateAnimation(int transit, boolean enter, int nextAnim)返回值Animation。
FragmentTransaction中的setCustomAnimations()方法,两参数类型和四参数类型都可用。
所以一般还是用v4包的这个版本,一是兼容性比较好,另外View Animation其实基本可以满足转场动画的需要。
代码例子:
三、Fragment嵌套Fragment要用getChildFragmentManager
Fragment放ViewPager,ViewPager里面是fragment。第一次进入没问题,再次进入ViewPager的fragment时里面内容就没了,数据丢失。
解决方案:
阿里P7Android高级架构进阶视频免费学习请点击:https://space.bilibili.com/474380680
参考:https://www.jianshu.com/p/6e7eda607acc
https://blog.csdn.net/shensky711/article/details/53132952
https://www.cnblogs.com/feng-ye/p/6435158.html