Fragment 源码学习,从源码理解 Fragment 生命周期

基于 support-fragment-26.0.0-alpha1

Fragment 的创建

Fragment 的使用离不开 FragmentActivity ,或者说 Fragment 必须依附于 FragmentActivity。

Fragment 可以在直接在 FragmentActivity 创建的时候,声明在 xml 文件之中。也可以在 Activity 创建以后,动态的创建。

  1. 方式一

     <?xml version="1.0" encoding="utf-8"?>
     <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
     
         <fragment
            android:id="@+id/test_frament"
            class="xxx.xxx.xxx.xxFragment"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    
     </LinearLayout>
    
  2. 方式二

     getSupportFragmentManager().beginTransaction().replace(R.id.fragment, new xxFragment()).commit();
    

这里有个问题?

Fragment 本身不是一个 View 的子类。
在方式二中我们知道我们 new 了一个 Fragment 交给 FragmentTransaction
那么!方式一是如何创建 Fragment的 ?

在前面阅读LayoutInflater 源码 我们可以得知,xml 里面声明的 View 都是通过 LayoutInflater 创建。那么 FragmentActivity 如何通过 xml 创建 Fragment 呢?

FragmentActivity 从 xml 创建 Fragment

先看下 FragmentActivity 的继承关系

fragment_01.png
onCreateView 方法创建 Fragment

在 BaseFragmentActivityApi14 中发现以下代码

@Override
public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
    final View v = dispatchFragmentsOnCreateView(parent, name, context, attrs);
    if (v == null) {
        return super.onCreateView(parent, name, context, attrs);
    }
    return v;
}

@Override
public View onCreateView(String name, Context context, AttributeSet attrs) {
    final View v = dispatchFragmentsOnCreateView(null, name, context, attrs);
    if (v == null) {
        return super.onCreateView(name, context, attrs);
    }
    return v;
}

abstract View dispatchFragmentsOnCreateView(View parent, String name,
        Context context, AttributeSet attrs);

这里看到 BaseFragmentActivityApi14 继承了 onCreateView 方法,并且声明了一个 dispatchFragmentsOnCreateView 方法。

FragmentActivity 实现了 dispatchFragmentsOnCreateView

@Override
final View dispatchFragmentsOnCreateView(View parent, String name, Context context,
        AttributeSet attrs) {
    return mFragments.onCreateView(parent, name, context, attrs);
}

最终 FragmentManager 中找到了 onCreateView 负责创建 Fragment

@Override
public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
    if (!"fragment".equals(name)) {
        return null;
    }

    ……
    if (fragment == null) {
        fragment = mContainer.instantiate(context, fname, null);
        ……
        addFragment(fragment, true);
        ……
    }……
    return fragment.mView;
}

FragmentContainer 中 instantiate 方法

public Fragment instantiate(Context context, String className, Bundle arguments) {
    return Fragment.instantiate(context, className, arguments);
}

然后又回到了 Fragment 中

public static Fragment instantiate(Context context, String fname, @Nullable Bundle args) {
    try {
        Class<?> clazz = sClassMap.get(fname);
        ……
        Fragment f = (Fragment)clazz.newInstance();
        ……
        return f;
    } ……
}    

可以看出,最终还是用了反射创建了 Fragment。 并且返回 fragment.mView 给 onCreateView

谁调用 onCreateView ?

先看一段 LayoutInflater 中 createViewFromTag() 方法

try {
    View view;
    if (mFactory2 != null) {
        view = mFactory2.onCreateView(parent, name, context, attrs);
    } else if (mFactory != null) {
        view = mFactory.onCreateView(name, context, attrs);
    } else {
        view = null;
    }
    if (view == null && mPrivateFactory != null) {
        view = mPrivateFactory.onCreateView(parent, name, context, attrs);
    }
    if (view == null) {
        final Object lastContext = mConstructorArgs[0];
        mConstructorArgs[0] = context;
        try {
            if (-1 == name.indexOf('.')) {
                view = onCreateView(parent, name, attrs);
            } else {
                view = createView(name, null, attrs);
            }
        } finally {
            mConstructorArgs[0] = lastContext;
        }
    }
    return view;

LayoutInflater 源码 我们讲到 mFactory2、mFactory、mPrivateFactory 全部为 null ,其实并不严谨。因为 Activity 也是一个 Factory2 的实现。

在 Activity 的 attach() 方法调用了

final void attach(Context context, ActivityThread aThread,
        Instrumentation instr, IBinder token, int ident,
        Application application, Intent intent, ActivityInfo info,
        CharSequence title, Activity parent, String id,
        NonConfigurationInstances lastNonConfigurationInstances,
        Configuration config, String referrer, IVoiceInteractor voiceInteractor,
        Window window) {
    ……
    mWindow.getLayoutInflater().setPrivateFactory(this);
    ……
}

而 BaseFragmentActivityApi14 又一次重载了 Activity 实现的 Factory2. onCreateView 。并拦截 <fragment> 标签交给 FragmentActivity 的 dispatchFragmentsOnCreateView() 方法。

总结一个简单的 UML 图

fragment_02.png

Fragment 执行生命周期

跟随 FragmentActivity 生命周期

在 FragmentActivity 的 onCreate() 中

 protected void onCreate(@Nullable Bundle savedInstanceState) {
    mFragments.attachHost(null /*parent*/);

    super.onCreate(savedInstanceState);
    ……
    mFragments.dispatchCreate();
}

public void dispatchCreate() {
    mHost.mFragmentManager.dispatchCreate();
}

public void dispatchCreate() {
    mStateSaved = false;
    mExecutingActions = true;
    moveToState(Fragment.CREATED, false);
    mExecutingActions = false;
}    

其中 moveToState(Fragment.CREATED, false) 会执行 Fragment 的 onCreate() 方法。

然后在 onStart() 方法中调用 mFragments.dispatchStart() ,执行 Fragment 的 onStart()方法 。

然后在 onResume() 是会调用 mHandler.sendEmptyMessage(MSG_RESUME_PENDING)

final Handler mHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case MSG_REALLY_STOPPED:
                if (mStopped) {
                    doReallyStop(false);
                }
                break;
            case MSG_RESUME_PENDING:
                onResumeFragments();
                mFragments.execPendingActions();
                break;
            default:
                super.handleMessage(msg);
        }
    }

};

接着会执行 onResumeFragments() -> mFragments.dispatchResume() , 执行 Fragment 的 onResume() 方法。

以此类推 Fragment 的生命周期跟随 FragmentActivity 的生命周期依次执行。

在 FragmentActivity 中动态添加 Fragment

在 FragmentActivity 中动态添加 Fragment 需要获得一个 FragmentTransaction

然后通过 FragmentTransaction.replace(R.id.fragment, new xxFragment()) 或者 FragmentTransaction.add(R.id.fragment, new xxFragment()) 添加一个创建的 Fragment 到 FragmentActivity(其实是 FragmentManager)

最后通过 FragmentTransaction.commit() 显示 Fragment。

获得 FragmentTransaction

获得 FragmentTransaction 首先获得 FragmentManager 。

public FragmentManager getSupportFragmentManager() {
    return mFragments.getSupportFragmentManager();
}

mFragments 是一个 FragmentController

final FragmentController mFragments = FragmentController.createController(new HostCallbacks());

FragmentController 的所有方法,都是包裹这 HostCallbacks() 来实现的。HostCallbacks 是 FragmentHostCallback 的子类

public FragmentManager getSupportFragmentManager() {
    return mHost.getFragmentManagerImpl();
}

其中 mHost 就是 HostCallbacks 的实例。HostCallbacks 继承 FragmentHostCallback

FragmentManagerImpl getFragmentManagerImpl() {
    return mFragmentManager;
}

在 FragmentHostCallback 中有成员变量

final FragmentManagerImpl mFragmentManager = new FragmentManagerImpl();

所以 FragmentTransaction 由 FragmentManagerImpl 创建。FragmentManagerImpl 又是 FragmentManager 的实例。

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

所以最终我们获得的 FragmentTransaction 是一个 BackStackRecord 实例。

获得 FragmentTransaction 的 add() 、replace()

这两个方法都在 BackStackRecord 中 ,有很多 add()、replace() 方法,这里贴两个重要的

@Override
public FragmentTransaction add(int containerViewId, Fragment fragment) {
    doAddOp(containerViewId, fragment, null, OP_ADD);
    return this;
}

@Override
public FragmentTransaction replace(int containerViewId, Fragment fragment, String tag) {
    if (containerViewId == 0) {
        throw new IllegalArgumentException("Must use non-zero containerViewId");
    }

    doAddOp(containerViewId, fragment, tag, OP_REPLACE);
    return this;
}

可以看出无论 add()、replace() 最终都调用 doAddOp(int containerViewId, Fragment fragment, String tag, int opcmd) 方法,只是 opcmd 值不同。

最终会添加一个 Op 对象

private void doAddOp(int containerViewId, Fragment fragment, String tag, int opcmd) {
    ……
    addOp(new Op(opcmd, fragment));
}

void addOp(Op op) {
    mOps.add(op);
    op.enterAnim = mEnterAnim;
    op.exitAnim = mExitAnim;
    op.popEnterAnim = mPopEnterAnim;
    op.popExitAnim = mPopExitAnim;
}
获得 FragmentTransaction 的 commit()

commit() 同样在 BackStackRecord 中实现。

@Override
public int commit() {
    return commitInternal(false);
}

然后执行

int commitInternal(boolean allowStateLoss) {
    ……
    mCommitted = true;
    if (mAddToBackStack) {
        mIndex = mManager.allocBackStackIndex(this);
    } else {
        mIndex = -1;
    }
    mManager.enqueueAction(this, allowStateLoss);
    return mIndex;
}

mIndex 是 BackStackRecord 在 FragmentManager 中保存的一个 ArrayList 的位置。

然后执行

public void enqueueAction(OpGenerator action, boolean allowStateLoss) {
    if (!allowStateLoss) {
        checkStateLoss();
    }
    synchronized (this) {
        ……
        scheduleCommit();
    }
}

接着执行

private void scheduleCommit() {
    synchronized (this) {
        boolean postponeReady =
                mPostponedTransactions != null && !mPostponedTransactions.isEmpty();
        boolean pendingReady = mPendingActions != null && mPendingActions.size() == 1;
        if (postponeReady || pendingReady) {
            mHost.getHandler().removeCallbacks(mExecCommit);
            mHost.getHandler().post(mExecCommit);
        }
    }
}

mExecCommit 是一个 Runnable

Runnable mExecCommit = new Runnable() {
    @Override
    public void run() {
        execPendingActions();
    }
};

然后就快到关键方法

public boolean execPendingActions() {
    ensureExecReady(true);

    boolean didSomething = false;
    while (generateOpsForPendingActions(mTmpRecords, mTmpIsPop)) {
        mExecutingActions = true;
        try {
            optimizeAndExecuteOps(mTmpRecords, mTmpIsPop);
        } finally {
            cleanupExec();
        }
        didSomething = true;
    }

    doPendingDeferredStart();

    return didSomething;
}

接着执行

private void optimizeAndExecuteOps(ArrayList<BackStackRecord> records,
        ArrayList<Boolean> isRecordPop) {
    ……
    int startIndex = 0;
    for (int recordNum = 0; recordNum < numRecords; recordNum++) {
            ……
            executeOpsTogether(records, isRecordPop, recordNum, optimizeEnd);
            ……
        }
    }
    ……
}

然后到了 executeOpsTogether

private void executeOpsTogether(ArrayList<BackStackRecord> records,
        ArrayList<Boolean> isRecordPop, int startIndex, int endIndex) {
    ……
    if (!allowOptimization) {
        FragmentTransition.startTransitions(this, records, isRecordPop, startIndex, endIndex,
                false);
    }
    executeOps(records, isRecordPop, startIndex, endIndex);
    ……
}

其中 FragmentTransition.startTransitions 最终会执行 addToFirstInLastOut

然后执行 manager.moveToState(fragment, Fragment.CREATED, 0, 0, false);

在 moveToState 中,会执行 Fragment 的 onAttach() 方法

其中的 executeOps(records, isRecordPop, startIndex, endIndex) 之中执行 void executeOps()

mManager.moveToState(mManager.mCurState, true);

因为此时 Activity 已经是 Resume 状态,所以 mManager.mCurState == RESUMED

然后 mManager.moveToState 会一次执行
Fragment.performCreateView()
Fragment.performActivityCreated()
Fragment.performStart()
Fragment.performResume()

通过上面可以发现 void moveToState(Fragment f, int newState, int transit, int transitionStyle,boolean keepActive) 是最关键的方法。Fragment 的各个状态都是通过这个方法进行切换的。

void moveToState(Fragment f, int newState, int transit, int transitionStyle,
        boolean keepActive) {
    ……
    if (f.mState <= newState) { // Fragment 从后台到显示
        ……
        switch (f.mState) {
            case Fragment.INITIALIZING:
                if (newState > Fragment.INITIALIZING) {
                    ……
                    f.onAttach(mHost.getContext());
                    ……
                }

            case Fragment.CREATED:
                ……
                if (newState > Fragment.CREATED) {
                        ……
                        f.mView = f.performCreateView(f.getLayoutInflater(
                                f.mSavedFragmentState), container, f.mSavedFragmentState);
                        ……
                    }

                    f.performActivityCreated(f.mSavedFragmentState);
                    ……
                }
            case Fragment.ACTIVITY_CREATED:
                if (newState > Fragment.ACTIVITY_CREATED) {
                    f.mState = Fragment.STOPPED;
                }
            case Fragment.STOPPED:
                if (newState > Fragment.STOPPED) {
                    if (DEBUG) Log.v(TAG, "moveto STARTED: " + f);
                    f.performStart();
                    dispatchOnFragmentStarted(f, false);
                }
            case Fragment.STARTED:
                if (newState > Fragment.STARTED) {
                    if (DEBUG) Log.v(TAG, "moveto RESUMED: " + f);
                    f.performResume();
                    dispatchOnFragmentResumed(f, false);
                    f.mSavedFragmentState = null;
                    f.mSavedViewState = null;
                }
        }
    } else if (f.mState > newState) {// Fragment 从显示到后台
        switch (f.mState) {
            case Fragment.RESUMED:
                if (newState < Fragment.RESUMED) {
                    if (DEBUG) Log.v(TAG, "movefrom RESUMED: " + f);
                    f.performPause();
                    dispatchOnFragmentPaused(f, false);
                }
            case Fragment.STARTED:
                if (newState < Fragment.STARTED) {
                    if (DEBUG) Log.v(TAG, "movefrom STARTED: " + f);
                    f.performStop();
                    dispatchOnFragmentStopped(f, false);
                }
            case Fragment.STOPPED:
                if (newState < Fragment.STOPPED) {
                    if (DEBUG) Log.v(TAG, "movefrom STOPPED: " + f);
                    f.performReallyStop();
                }
            case Fragment.ACTIVITY_CREATED:
                if (newState < Fragment.ACTIVITY_CREATED) {
                    ……
                    f.performDestroyView();
                    dispatchOnFragmentViewDestroyed(f, false);
                    ……
                }
            case Fragment.CREATED:
                if (newState < Fragment.CREATED) {
                    ……
                }
        }
    }
    ……
}

参考资料

安卓基础:Activity/Fragment 生命周期

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,200评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,526评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,321评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,601评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,446评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,345评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,753评论 3 387
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,405评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,712评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,743评论 2 314
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,529评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,369评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,770评论 3 300
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,026评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,301评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,732评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,927评论 2 336

推荐阅读更多精彩内容