Android:从源码看FragmentManager如何工作

一个Activity中,在某一个容器中,更换不同的Fragment,从而显示不同的界面,这个场景相信大家已经非常熟悉了,也知道Activity是通过FragmentManager来管理嵌入的Fragments的,所以今天就来看看FragmentManager是如何工作的。

我们以继承AppCompatActivity来分析。

我们常用的几种操作大致如下:

java 复制代码
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对象实例。

java 复制代码
FragmentManager fragmentManager = getSupportFragmentManager();

那我们就看看getSupportFragmentManager干了什么。

java 复制代码
FragmentActivity.class

    @NonNull
    public FragmentManager getSupportFragmentManager() {
        return this.mFragments.getSupportFragmentManager();
    }

mFragments是 FragmentController 实例,声明时直接初始化final对象。

java 复制代码
final FragmentController mFragments = FragmentController.createController(new HostCallbacks());

这了出现了一个HostCallbacks,继承自FragmentHostCallback,看看它的初始化。

java 复制代码
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赋值。

java 复制代码
    private FragmentController(FragmentHostCallback<?> callbacks) {
        this.mHost = callbacks;
    }

这样的话,FragmentController mFragments就初始化完成。回过头来再看getSupportFragmentManager的过程

java 复制代码
//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实例。

java 复制代码
FragmentManager fragmentManager = getSupportFragmentManager();

拿到fragmengManager后,接着开启一个事务FragmentTransaction。

java 复制代码
FragmentTransaction transaction = fragmentManager.beginTransaction();

调用下面接口:

java 复制代码
//FragmentManagerImpl.class

    @NonNull
    public FragmentTransaction beginTransaction() {
        return new BackStackRecord(this);
    }

我们看到了一个新的类BackStackRecord,看名字大概是回退栈的意思,它继承自FragmentTransaction,它记录了Fragment的索引等信息,每次beginTransaction都会产生一个BackStackRecord对象,BackStackRecord中持有了当前FragmentManagerImpl对象,操作Fragment的动作,都是由这里入口,然后再调用基类FragmentTransaction的方法,将每个动作都添加到Op对象中,比如下面:

java 复制代码
transaction.hide
java 复制代码
//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不会立即执行,它会把事务放在队列里,会在线程下一次执行时进行操作。

java 复制代码
//commit调用commitInternal

    int commitInternal(boolean allowStateLoss) {
        ......
        mManager.enqueueAction(this, allowStateLoss);
        return mIndex;
    }

commitNow会立即执行事务。

java 复制代码
//commitNow会调用FragmentManagerImpl的execSingleAction

    @Override
    public void commitNow() {
        disallowAddToBackStack();
        mManager.execSingleAction(this, false);
    }

这样整个FragmentManager就开始工作了,后面我们会想想讲解每一种操作的具体源码。

相关推荐
4***997412 小时前
Kotlin序列处理
android·开发语言·kotlin
t***D26412 小时前
Kotlin在服务端开发中的生态建设
android·开发语言·kotlin
玲珑Felone12 小时前
flutter 状态管理--InheritedWidget、Provider原理解析
android·flutter·ios
BoomHe12 小时前
车载应用配置系统签名
android·android studio
路人甲ing..14 小时前
用 Android Studio 自带的模拟 Android Emulator 调试
android·java·ide·ubuntu·kotlin·android studio
路人甲ing..14 小时前
Android Studio 模拟器报错 The emulator process for AVD xxxxx has terminated.
android·java·ide·kotlin·android studio
弥巷15 小时前
【Android】 View事件分发机制源码分析
android·java
wanna16 小时前
安卓自学小笔记第一弹
android·笔记
Kapaseker16 小时前
五分钟实战 Compose 展开/收起动画
android·kotlin