简介:
作为一个android开发者,UI架构设计、开发肯定是必备技能,至少android应用开发还没Web端开发分的那么细,前端/后端/数据库,android从UI到数据存储都在客户端完成,而Fragment作为系统提供的页面级别的组件类,在构建复杂的页面布局和页面功能复用上有着很重要的地位,它和Activity一样有生命周期,当然就会有一个对Fragment管理类FragmentManager,这篇的目标主要对Fragment的生命周期以及Fragment是如何被管理的去解读源码,从而解答开发中Fragment常见的一些问题。
1. 主要涉及的类及文件:
FragmentManager.java
+ FragmentManager.class
+ FragmentManagerImpl.class
BackStackRecord.java
FragmentHostCallback.java
FragmentTransaction.java
2. Fragment基本使用
用过Fragment的童鞋应该清楚FragmentManager对Fragment的操作有以下几类行为:
add/remove、replace、hide/show、detach/attach。
当添加或展示一个fragment时,需要通过add或replace的方式将fragment绑定到一个containerId上,简单的描述一下代码流程:
先获取到当前activity或fragment的fragmentmanager;
然后通过FragmentManager#beginTransaction()获取到FragmentTransaction对象(其实就是BackstackRecord对象);
接着通过FragmentTransaction对象通过add或replace的方式将需要展示的fragment添加进来,然后show()展示fragment。
3. FragmentManager的获取方式
一般在activity中直接通过getFragmentManager或getSupportFragmentManager来获取,在Fragment中通过getChildFragmentManager或getSupportChildFragmentManager来获取。
那这两种获取的方式有和区别?获取到的FragmentManager之间是否有联系呢?
先来看看Activity中getFragmentManager方法:
/** * Return the FragmentManager for interacting with fragments associated * with this activity. */ public FragmentManager getFragmentManager() { return mFragments.getFragmentManager(); }
|
那mFragments又是什么对象呢?
在activity的成员变量定义的地方可以看到mFragments:
final FragmentController mFragments = FragmentController
.createController(new HostCallbacks());
原来时FragmentController对象,这里暂时先不看这个类。
那Fragment中的getChildFragmentManager又是如何定义的呢?
/** * Return the FragmentManager for interacting with fragments associated * with this fragment's activity. Note that this will be non-null slightly * before {@link #getActivity()}, during the time from when the fragment is * placed in a {@link FragmentTransaction} until it is committed and * attached to its activity. * * <p>If this Fragment is a child of another Fragment, the FragmentManager * returned here will be the parent's {@link #getChildFragmentManager()}. */ final public FragmentManager getFragmentManager() { return mFragmentManager; }
/** * Return a private FragmentManager for placing and managing Fragments * inside of this Fragment. */ final public FragmentManager getChildFragmentManager() { if (mChildFragmentManager == null) { instantiateChildFragmentManager(); if (mState >= RESUMED) { mChildFragmentManager.dispatchResume(); } else if (mState >= STARTED) { mChildFragmentManager.dispatchStart(); } else if (mState >= ACTIVITY_CREATED) { mChildFragmentManager.dispatchActivityCreated(); } else if (mState >= CREATED) { mChildFragmentManager.dispatchCreate(); } } return mChildFragmentManager; }
|
可以看到实例化childFragmentManager的地方在instantiateChildFragmentManager()这个方法中:
void instantiateChildFragmentManager() { mChildFragmentManager = new FragmentManagerImpl(); mChildFragmentManager.attachController(mHost, new FragmentContainer() { @Override @Nullable public View onFindViewById(int id) { if (mView == null) { throw new IllegalStateException("Fragment does not have a view"); } return mView.findViewById(id); }
@Override public boolean onHasView() { return (mView != null); } }, this); } |
原来在fragment中直接实例化了一个新的fragmentManager对象,但注意一下attachController方法,其中参数mHost是指fragment所附加到的activity对象,等下面讲解FragmentManager对象时在做介绍。
上面的getChildFragmentManager代码框中其实还有一个方法getFragmentManager,用于获取activity的fragmentmanager对象的,那是如何获取的呢?如果一个fragment嵌套fragment,那么这个activity的fragmentmanager对象又是如何传递下去的呢?
其实是跳过调用fragment# instantiate方法通过mHost对象类给当前fragment的mFragmentManager赋值的,所以当前fragment也就可以获取到Activity的fragmentmanager了,关于mHost对象以及fragment和activity之间的关联关系是如何建立的在下一节讲解。
4. FragmentManager类
现在开始对FragmentManager类做一个大致的了解,了解其作用以及如何对fragment进行管理的。首先看一下类的定义,FragmentManager是一个抽象类,在其同文件下有一个实现类FragmentManagerImpl,那就直接看impl类即可。
从fragment基本使用来看,获取到FragmentManager之后便开始事务,那看一下beginTransaction()方法的定义:
FragmentManager: /** * Start a series of edit operations on the Fragments associated with * this FragmentManager. * * <p>Note: A fragment transaction can only be created/committed prior * to an activity saving its state. If you try to commit a transaction * after {@link FragmentActivity#onSaveInstanceState FragmentActivity.onSaveInstanceState()} * (and prior to a following {@link FragmentActivity#onStart FragmentActivity.onStart} * or {@link FragmentActivity#onResume FragmentActivity.onResume()}, you will get an error. * This is because the framework takes care of saving your current fragments * in the state, and if changes are made after the state is saved then they * will be lost.</p> */ public abstract FragmentTransaction beginTransaction(); FragmentManagerImpl:
@Override public FragmentTransaction beginTransaction() { return new BackStackRecord(this); } |
可以看到impl中直接实例化了一个BackStackRecord对象。那接着后面的add、replace、show/hide等动作就是BackStackRecord对象上执行的。那FragmentManager的作用就这么多了吗?当然不是,里面还有一个比较重要的方法moveToState(),根据fragment的状态来对fragment的属性进行赋值等。具体请看FragmentManager一章。
5. BackstackRecord相关的操作
在BackStackRecord.java类中,定义了两个类:BackStackState和BackStackReocrd。
BackStackState实现了Parcelable接口,说明是可以被序列化的,并且可以实例化一个BackStackReocrd对象,这相当于BackStackRecord也是可以序列化传输的。
BackStackRecord继承制FragmentTransaction并实现了Runnable,内部定义了Op对象,Op是一个双向链表结构,用于保存BackStackRecord的所有操作以及对用的Fragment。在BackStackRecord的内部成员变量中保存了Op的head和tail对象,刚创建的BackStackRecord的head和tail指向同一位置,当BackStackRecord调用不同的操作方法时,tail会指向最后一个操作对象,并且每一个op对象的前后对象都是相关联的。
BackStackRecord的作用时记录一次Transaction的提交中所有的操作,保存操作的命令和对应的fragment,在正向操作时会根据Op的顺序,对op命令执行对应的FM对fragment的操作。在反向操作时,根据Op的顺序对命令执行相反的FM操作。
BackStackRecord和FragmentManager的相互关系时耦合的,两者相互依赖但分工明确,
BackStackRecord的主要职责就是记录操作状态,FragmentManager是对Fragment操作者。
下面简单说明一下Fragment的操作流程:
先获取到FragmentManager->beginTransaction获取到BackStackRecord对象;
->调用transaction的接口操作方法添加、删除、显示、隐藏等并保存相关操作;
->调用transaction的commit方法;
->BackStackRecord调用FragmentManager. enqueueAction方法,并将当前BackStackRecord对象作为参数传递;
->调用FragmentManager的handler发送mExecCommit消息;
->最后执行的是FragmentManager#execPendingActions;
->然后循环执行pendingActions中所有的BackStackRecord的run方法
->BackStackRecord在run方法中根据Op的操作对象的cmd又会调用对用的FM的方法,在FM的moveToState方法中会调用Fragment的对应的生命周期函数。
- 总结:
以上只是对Fragment相关类做一个简短的说明介绍,其实FragmentManager和BackStackRecord对象内部实现还是比较复杂的,在后面文章中会对其具体的细节详细介绍。