对于Fragment,相信做过android的肯定或多或少的都用过,但是你对它的实现原理是否知道,这里我们就从一个大的方向来看看它是如何设计的。
Fragment是有生命周期的,和Activity类似,我们可以把fragment看成是activity的一部分,fragment的生命周期其实就是由activity来控制的,只不过fragment内部又做了一些细致的划分,这也就是为什么我们会在fragment中多出一些方法的回调,这里有一个点需要注意,activity并不是直接控制fragment的,他们中间隔着一个FragmentManager,那这个FragmentManager又是什么呢?我们可以理解为是一个可以感知activity生命周期的,负责管理fragment的类,它里面有一个集合就是负责收集添加进activity的fragment,也就是ArrayList,我们知道,在fragment中能做一些只能在activity中做的事情,这个又是怎么实现的呢?这个用到的就是回调了,涉及到的一个抽象类是FragmentHostCallback,这个类在FragmentActivity中有实现,当在fragment中使用调用startActivity()时,其实最终调用到的还是Activity中startActivity(),下面就从源码中来看看,主要是看流程,不会涉及到细节。
先来看下FragmentActivity中定义的一个成员变量:
final FragmentController mFragments = FragmentController.createController(new HostCallbacks());
这里涉及到两个类:
1、FragmentController :主要作用是Activity到Fragment通信;
2、HostCallbacks:主要作用是Fragment到Activity通信,它继承自FragmentHostCallback;
这里先来看下HostCallbacks的构造方法:
class HostCallbacks extends FragmentHostCallback<FragmentActivity> {
public HostCallbacks() {
super(FragmentActivity.this /*fragmentActivity*/);
}
...
}
又调用了父类的构造方法,并将FragmentActivity传进去,跟着往下走:
public abstract class FragmentHostCallback<E> extends FragmentContainer {
private final Activity mActivity;
final Context mContext;
private final Handler mHandler;
final int mWindowAnimations;
final FragmentManagerImpl mFragmentManager = new FragmentManagerImpl();
private SimpleArrayMap<String, LoaderManager> mAllLoaderManagers;
private LoaderManagerImpl mLoaderManager;
private boolean mCheckedForLoaderManager;
private boolean mLoadersStarted;
public FragmentHostCallback(Context context, Handler handler, int windowAnimations) {
this(null /*activity*/, context, handler, windowAnimations);
}
FragmentHostCallback(FragmentActivity activity) {
this(activity, activity /*context*/, activity.mHandler, 0 /*windowAnimations*/);
}
FragmentHostCallback(Activity activity, Context context, Handler handler,
int windowAnimations) {
mActivity = activity;
mContext = context;
mHandler = handler;
mWindowAnimations = windowAnimations;
}
public void onStartActivityFromFragment(Fragment fragment, Intent intent, int requestCode) {
if (requestCode != -1) {
throw new IllegalStateException(
"Starting activity with a requestCode requires a FragmentActivity host");
}
mContext.startActivity(intent);
}
...
}
可以看到这里将activity和handler保存了起来,这样当Fragment中有需要执行Fctivity的方法时,就可以通过这个保存的变量来实现了,比如,当在fragment中调用startActivity()时,最后调用到的就是这里的onStartActivityFromFragment(),还有其他一些Fragment回调到Activity的方法都是定义在这里。这里有一个需要特别注意的属性mFragmentManager ,它就是管理Fragment的,activity涉及到对fragment的操作都是通过他来实现的,比如activity对fragment生命周期分发。
在来FragmentActivity的各个生命周期方法中可以发现,都会使用到mFragments,这里以FragmentActivity的onCreate()方法为例,来看下他对mFragments的使用:
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
mFragments.attachHost(null /*parent*/);
super.onCreate(savedInstanceState);
//以下部分是对Fragment状态的恢复,想进一步了解的可以看下上一篇: Fragment之setRetainInstance详解
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
mFragments.restoreLoaderNonConfig(nc.loaders);
}
if (savedInstanceState != null) {
Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
mFragments.restoreAllState(p, nc != null ? nc.fragments : null);
}
//Fragment将会执行对应的生命周期方法,其他的生命周期类似,这里就不一一去看了
mFragments.dispatchCreate();
}
可以看到这里全是对Fragment的处理,其中mFragments.dispatchCreate()是分发对应的生命周期,fragment中的生命周期都是以这种方式分发下去的,这也就是fragment和activity的生命周期是对应的,这里在主要来看下mFragments.attachHost(null /parent/),看下它里面做了些什么:
public class FragmentController {
private final FragmentHostCallback<?> mHost;
public static final FragmentController createController(FragmentHostCallback<?> callbacks) {
return new FragmentController(callbacks);
}
private FragmentController(FragmentHostCallback<?> callbacks) {
mHost = callbacks;
}
public FragmentManager getSupportFragmentManager() {
return mHost.getFragmentManagerImpl();
}
public LoaderManager getSupportLoaderManager() {
return mHost.getLoaderManagerImpl();
}
public void attachHost(Fragment parent) {
mHost.mFragmentManager.attachController(
mHost, mHost /*container*/, parent);
}
...
}
先看下它的构造方法,将HostCallbacks 对象保存到了mHost中,再来看下它的attacHost()方法,使用到了mFragmentManager,它是在FragmentHostCallback中实例化的,上面也有提到,它是一个FragmentManagerImpl对象,跟着attachController()这个方法进去看看:
final class FragmentManagerImpl extends FragmentManager implements LayoutInflaterFactory {
...
FragmentHostCallback mHost;
FragmentContainer mContainer;
Fragment mParent;
public void attachController(FragmentHostCallback host,
FragmentContainer container, Fragment parent) {
if (mHost != null) throw new IllegalStateException("Already attached");
mHost = host;
mContainer = container;
mParent = parent;
}
....
}
也没什么,就是初始化一些变量,这里注意这个mHost,当在fragment需要调回到activity时,用到的就是mHost(也就是FragmentHostCallback),到这里,对于FragmentManager的准备工作就算是完成了,接下开就是使用了,下一篇再来介绍fragment的工作流程。
#总结
1、链接Activity和Fragment的点是FragmentHostCallback;
2、Fragment向Activity通信通过FragmentHostCallback定义的方法进行回调;
3、FragmentHostCallback中实例化了FragmentManagerImpl ,管理着所有添加的Fragment的,Activity向Fragment通信就是通过他来实现的;
4、为了剥离Activity向Fragment的通信,使用FragmentController 对FragmentManagerImpl 进行代理,这样就可以使用FragmentController 对Fragment进行通信了。