一个Activity中,在某一个容器中,更换不同的Fragment,从而显示不同的界面,这个场景相信大家已经非常熟悉了,也知道Activity是通过FragmentManager来管理嵌入的Fragments的,所以今天就来看看FragmentManager是如何工作的。
我们以继承AppCompatActivity来分析。
我们常用的几种操作大致如下:
FragmentManager fragmentManager = getSupportFragmentManager();
Fragment f1 = new Fragment();
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.add(f1,"tag");
transaction.hide(f1);
transaction.show(f1);
transaction.replace(R.id.layout1,f1);
transaction.remove(f1);
首先我们要获得FragmentManager对象实例。
FragmentManager fragmentManager = getSupportFragmentManager();
那我们就看看getSupportFragmentManager干了什么。
FragmentActivity.class
@NonNull
public FragmentManager getSupportFragmentManager() {
return this.mFragments.getSupportFragmentManager();
}
mFragments是 FragmentController 实例,声明时直接初始化final对象。
final FragmentController mFragments = FragmentController.createController(new HostCallbacks());
这了出现了一个HostCallbacks,继承自FragmentHostCallback,看看它的初始化。
public HostCallbacks() {
super(FragmentActivity.this);
}
基类构造如下:
FragmentHostCallback(@NonNull FragmentActivity activity) {
this(activity, activity, new Handler(), 0);
}
FragmentHostCallback(@Nullable Activity activity, @NonNull Context context, @NonNull Handler handler, int windowAnimations) {
//实际执行操作的是FragmentManagerImpl实例
this.mFragmentManager = new FragmentManagerImpl();
this.mActivity = activity;
this.mContext = (Context)Preconditions.checkNotNull(context, "context == null");
//handler,后面会用到
this.mHandler = (Handler)Preconditions.checkNotNull(handler, "handler == null");
this.mWindowAnimations = windowAnimations;
}
重点是FragmentManagerImpl,具体的操作都交给了FragmentManagerImpl对象。
再回到FragmentController.createController,通过传递HostCallbacks参数,将对属性mHost赋值。
private FragmentController(FragmentHostCallback> callbacks) {
this.mHost = callbacks;
}
这样的话,FragmentController mFragments就初始化完成。回过头来再看getSupportFragmentManager的过程
//FragmentActivity.class
public FragmentManager getSupportFragmentManager() {
//调用FragmentController的getSupportFragmentManager
return this.mFragments.getSupportFragmentManager();
}
//FragmentController.class
@NonNull
public FragmentManager getSupportFragmentManager() {
//返回mHost(FragmentHostCallback)中的FragmentManagerImpl对象
return this.mHost.mFragmentManager;
}
所以下面这句话拿到的就是FragmentManagerImpl实例。
FragmentManager fragmentManager = getSupportFragmentManager();
拿到fragmengManager后,接着开启一个事务FragmentTransaction。
FragmentTransaction transaction = fragmentManager.beginTransaction();
调用下面接口:
//FragmentManagerImpl.class
@NonNull
public FragmentTransaction beginTransaction() {
return new BackStackRecord(this);
}
我们看到了一个新的类BackStackRecord,看名字大概是回退栈的意思,它继承自FragmentTransaction,它记录了Fragment的索引等信息,每次beginTransaction都会产生一个BackStackRecord对象,BackStackRecord中持有了当前FragmentManagerImpl对象,操作Fragment的动作,都是由这里入口,然后再调用基类FragmentTransaction的方法,将每个动作都添加到Op对象中,比如下面:
transaction.hide
//BackStackRecord.java
@NonNull
@Override
public FragmentTransaction hide(@NonNull Fragment fragment) {
if (fragment.mFragmentManager != null && fragment.mFragmentManager != mManager) {
throw new IllegalStateException("Cannot hide Fragment attached to "
+ "a different FragmentManager. Fragment " + fragment.toString() + " is already"
+ " attached to a FragmentManager.");
}
return super.hide(fragment);
}
//FragmentTransaction.java
@NonNull
public FragmentTransaction hide(@NonNull Fragment fragment) {
//添加Op到操作列表中
addOp(new Op(OP_HIDE, fragment));
return this;
}
当添加完一系列的动作后,操作并没有生效,我们需要调用commit或者commitNow来提交事务,才能看到最终的结果。
commit不会立即执行,它会把事务放在队列里,会在线程下一次执行时进行操作。
//commit调用commitInternal
int commitInternal(boolean allowStateLoss) {
......
mManager.enqueueAction(this, allowStateLoss);
return mIndex;
}
commitNow会立即执行事务。
//commitNow会调用FragmentManagerImpl的execSingleAction
@Override
public void commitNow() {
disallowAddToBackStack();
mManager.execSingleAction(this, false);
}
这样整个FragmentManager就开始工作了,后面我们会想想讲解每一种操作的具体源码。