通过源码解析 Fragment 启动过程

0x00

作为一名 Android 开发者,大家绝对都接触过 Fragment 开发,而且绝大多数人例如我一直都很难记住下图 Fragment 复杂的生命周期,更别说要将其与 Activity 的生命周期关联起来。


死背是无法解决问题的,若我们能从源码的角度对 Fragment 的启动过程进行分析,就能达到事半功倍的效果。那么我们选择上图中的第一部分入手吧。

下面我将会分析 Fragment 这一部分的启动过程,剩下部分的逻辑没有多大差异,所用的 Android SDK 版本为 23

0x01

一般情况下我们 MainActivity 需要显示一个 ContentFragment,代码可以这么写。

//MainActivity
public class MainActivity extends Activity{
  ContentFragment mContentFragment;
  
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mContentFragment = ContentFragment.newInstance(null);
    getFragmentManager()
        .beginTransaction()
        .replace(R.id.container,mContentFragment)
        .commit();
  }
}

同时为了方便起见,我大概介绍下我们即将遇到的几个类。第一次看的时候可能印象不深,但没关系,后面还会反复提起。


上面 UML 类图并不是完整的,但已经足够了。

  1. ActivityThread : 大名鼎鼎的 Android 入口类,我们的分析也将会从它开始
  1. Instrumentation : ActivityThread 的得力助手,帮助 ActivityThread 触发 Activity 的生命周期
  2. MainActivity : 就是上文提到例子中的 MainActivity 类,继承自 Activity
  3. HostCallbacks : Activity 的内部类,继承自 FragmentHostCallback
  4. FragmentHostCallback : 持有 Handler、FragmentManagerImpl 等等对象的引用,别的对象可以通过持有它的引用间接控制 FragmentManagerImpl 等等对象
  5. FragmentController : Activity 通过控制它间接向 FragmentManagerImpl 发出命令
  6. FragmentManagerImpl : 顾名思义,它继承自 FragmentManager,用来对 Fragment 进行管理,在 FragmentHostCallback 中被初始化
  7. BackStackRecord : 继承自 FragmentTransation 并实现了 Runnable,每次调用 FragmentManager 对象的 beginTransaction() 方法都会产生一个 BackStackRecord 对象,可以将其理解为对 Fragment 的一系列操作(即事务)
  8. Op : 每次对 Fragment 的操作都会产生一个 Op 对象,其表示双向链表的一个结点

哈哈,没印象无所谓...

0x02

那从哪里开始呢,我们注意到 Activity 类中有个 FragmentController 实例,那它是怎么初始化的?我们直接在 Activity 中搜索 FragmentController 关键字,即可找到如下代码:

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

原来在声明成员变量的同时初始化的呀,那也就是说在 Activity 被实例化时该成员变量也会被初始化,那么 Activity 又是在哪里被实例化的呢?作为一位看过 Activity 启动过程源码解析的男人,一下子就能想到 ActivityThread 的 performLaunchActivity 方法(当然,没看过 Activity 启动过程源码的朋友也没事,这篇文章分析的流程比那个简单多了,而且我们这里并不关注 Activity 的启动过程,看了这个或许对看那个有一定帮助),那我们去 ActivityThread 类的 performLaunchActivity 方法找下吧

//ActivityThread
Activity activity = null;
try {
    java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
    activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
    /*这个方法最终会通过反射调用 Activity 的无参构造方法*/
    //...
} catch (Exception e) {
    //...
}
//上面代码省略了一些非本次该关注的逻辑,下同

我们从 Activity 的实例化这里开始讲起吧

0x03

上文说到,Activity 会在 ActivityThread 的方法 performLaunchActivity 中通过反射实例化,相当于调用了它的无参构造方法,接着会触发 Activity 的成员变量 mFragments 的初始化,即

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

直接实例化了一个 HostCallbacks 对象并将其作为参数传入 FragmentController 类的 createController 静态方法中。

I

好的,我们先看看 HostCallbacks 初始化做了啥。

//HostCallbacks(因为 HostCallbacks 是 Activity 的内部类,所以是在 Activity.java 文件里)
public HostCallbacks() {
    super(Activity.this );
}

嗯,因为 HostCallbacks 是 Activity 的内部类,所以直接用 Activity.this 作为参数调用它父类的构造方法,通过上文我们知道它的父类是 FragmentHostCallback

//FragmentHostCallback
FragmentHostCallback(Activity 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;
}

我们可以了解到它最终调用了 FragmentHostCallback 四个参数的重载构造方法,并会将 Activity 、Handler 等等对象保存到它的成员变量中。上文说到 FragmentManagerImpl 会在 FragmentHostCallback 中被初始化,看来它不是在构造方法中被初始化,那我们到成员变量的声明处看看吧。

//FragmentHostCallback
final FragmentManagerImpl mFragmentManager = new FragmentManagerImpl();

又是在声明的同时初始化。FragmentManagerImpl 继承自抽象类 FragmentManager,FragmentManagerImpl 采用的是默认的构造方法,所以这部分的分析就到此为止了。对了,FragmentManagerImpl 和 FragmentManager 两个类都是在 FragmentManager.java 文件中的,而且不是内外部类关系,FragmentManagerImpl 类的声明如下

//FragmentManager
final class FragmentManagerImpl extends FragmentManager implements LayoutInflater.Factory2{
  //...
}

作用域是包级的,包名是 android.app

II

上一节后我们已经有了一个 HostCallback 对象,并将其作为参数传给 FragmentController 的 createController 静态方法,我们现在进去看看吧。

//FragmentController
public static final FragmentController createController(FragmentHostCallback<?> callbacks) {
    return new FragmentController(callbacks);
}

private FragmentController(FragmentHostCallback<?> callbacks) {
    mHost = callbacks;
}

原来 FragmentController 隐藏了自己的构造方法,createController 就如同工厂方法,最后令 FragmentController 对象持有了 HostCallbacks 对象的引用。这样 FragmentController 就能通过 HostCallbacks 对象的引用来间接调用 FragmentManagerImpl 了啦,因为你看上面 FragmentHostCallback 类中 mFragmentManager 的声明也是默认包级的。

阶段小结

在 Activity 实例化的过程中,初始化了它的成员变量 FragmentController,FragmentController 持有了 HostCallbacks 对象的引用,HostCallbacks 是 Activity 的内部类,HostCallbacks 用 Activity 对象作为参数调用自己父类 FragmentHostCallback 的构造方法,接着 FragmentHostCallback 会持有了 Activity、Handler 等等对象的引用,并在声明 mFragmentManager 成员变量的同时实例化 FragmentManagerImpl 对象。

0x04

在 ActivityThread 类的 performLounchActivity 方法里 Activity 被实例化后不久会被调用重量级的 attach 方法,我们试试到这方法下看看是否有我们需要的信息。

//Activity
mFragments.attachHost(null /*parent*/);

我们知道 mFragments 就是 FragmentController 对象的引用,看来这里确实有些初始化操作,那为什么是传入 null 呢?我们看下方法吧。

//FragmentManagerImpl
public void attachHost(Fragment parent) {
    mHost.mFragmentManager.attachController(
            mHost, mHost /*container*/, parent);
}

因为 Fragment 下也能有自己的子 Fragment,而现在我们的 Fragment 是在 Activity 下的,所以这里当然就直接传入 null 啦。我们再注意到本方法调用了 mHost 的 mFragmentManager 成员变量的 attachController 方法,我们只需关心方法的第一个参数。

//FragmentManagerImpl
public void attachController(FragmentHostCallback<?> host, FragmentContainer container,
        Fragment parent) {
    if (mHost != null) throw new IllegalStateException("Already attached");
    mHost = host;
    mContainer = container;
    mParent = parent;
}

嗯,现在 FragmentManagerImpl 对象也持有了 HostCallbacks 对象的引用。

阶段小结

这一部分我们关注的仅仅是 FragmentManagerImpl 对象持有了 HostCallbacks 对象的引用。

0x05

我们知道 Fragment 的生命周期与 Acitivty 的有对应关系,那么我们也就可以猜到 Activity 的生命周期方法被触发时,Activity 会同时触发 Fragment 对应的生命周期方法,而且是通过自己持有的 FragmentController 对象来触发的,我们来看看是不是这样子吧。Activity 生命周期第一个被调用的方法是 onCreate 方法,它是在哪里被触发的呢?现在就是 ActivityThread 的得力助手 Instrumentation 出场的时候了!
还是在 ActivityThread 的 performLounchActivity 方法中,我们发现如下代码

//ActivityThread
mInstrumentation.callActivityOnCreate(activity, r.state);

跳去 Instrumentation 类看看

//Instrumentation
public void callActivityOnCreate(Activity activity, Bundle icicle) {
    //...
    activity.performCreate(icicle);
    //...
}

调用了 performCreate 方法,注意这里的 activity 的运行时类型是 MainActivity,因为我们的 MainActivity 继承了 Activity,但 performCreate 方法是 final 的,MainActivity 无法重写,所以调用了其父类 Activity 的 performCreate 方法,我们去看下

//Activity
final void performCreate(Bundle icicle) {
    onCreate(icicle);
    //...
    performCreateCommon();
}

先调用 onCreate方法再调用 performCreateCommon方法,同时我们注意到 onCreate 方法最先被调用而 performCreateCommon 最后被调用,两个方法都会分别触发 Fragment 的生命周期方法,这样安排是有目的的。下面我们分别分析。

PS : 下面是一连串的调用,先休息下,揉揉眼睛,喝喝水吧。

I

因为 MainActivity 重写了 Activity 的 onCreate 方法,我们先再看下我们重写的 onCreate 方法。

//MainActivity
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mContentFragment = ContentFragment.newInstance(null);

getFragmentManager()
    .beginTransaction()
    .replace(R.id.container,mContentFragment)
    .commit();
}

这个方法做了挺多操作的,我们还是一个一个来哈。

I-I

首先调用了父类 Activity 的 onCreate 方法,我们去看看做了啥。

//Activity
@MainThread
@CallSuper
protected void onCreate(@Nullable Bundle savedInstanceState) {
    //...
    mFragments.dispatchCreate();
    //...
}

Activity 好懒哟,又让人家 FragmentController 干活,可怜的 FragmentController

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

FragmentController 深得 Activity 精髓,把活推给了 FragmentManagerImpl,原来 FragmentManagerImpl 才是苦力。

//FragmentManagerImpl
public void dispatchCreate() {
    //...
    moveToState(Fragment.CREATED, false);
}

void moveToState(int newState, boolean always) {
    moveToState(newState, 0, 0, always);
}

void moveToState(int newState, int transit, int transitStyle, boolean always) {
    if (mHost == null && newState != Fragment.INITIALIZING) {
        throw new IllegalStateException("No activity");
    }

    if (!always && mCurState == newState) {
        return;
    }

    mCurState = newState;
    if (mActive != null) {
        //...
    }
}

上面有三个方法被顺序调用,到了最后一个 moveToState 方法时我们只需关注它的参数 newState = Fragment.CREATEDalways = false,而默认情况下成员变量 mCurState = Fragment.INITIALIZINGmActive = null,所以该方法执行后只有一个值得我们关注的细节 mCurState = Fragment.CREATED

I-II

MainActivity 的父类的 onCreate 方法执行完后我们该关注 getFragmentManager 方法了,到 Activity 中看看这个方法吧。

//Activity
public FragmentManager getFragmentManager() {
    return mFragments.getFragmentManager();
}

//FragmentController
public FragmentManager getFragmentManager() {
    return mHost.getFragmentManagerImpl();
}

只是直接返回 HostCallbacks 对象持有的 FragmentManagerImpl 对象而已。

I-III

接下来就到了 FragmentManagerImpl 的 beginTransaction 方法了。

//FragmentManagerImpl
public FragmentTransaction beginTransaction() {
    return new BackStackRecord(this);
}

如我们所知,BackStackRecord 对象代表一系列对 Fragment 的操作,即事务,这里调用了 BackStackRecord 的构造方法并将 FragmentManagerImpl 自己作为参数传入。咱去看看构造方法做了啥。

//BackStackRecord
public BackStackRecord(FragmentManagerImpl manager) {
    mManager = manager;
}

这样 BackStackRecord 也持有了 FragmentManagerImpl 对象的引用。

I-Ⅳ

然后调用 BackStackRecord 的 replace 方法,即

//BackStackRecord
public FragmentTransaction replace(int containerViewId, Fragment fragment) {
    return replace(containerViewId, fragment, null);
}

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;
}

先调用 replace 两个参数的重载方法,在该方法里调用了 replace 三个参数的重载方法,同时参数 tag = null,在这个方法里首先判断传进的用来装载 Fragment 的容器的 ID 是否有效,接着调用 doAddOpp 方法,它第三个参数传入了的是 OP_REPLACE 常量。这里注意它最后返回了 this,也就是我们的链式调用的下一个方法还是 BackStackRecord 对象的,结合下面我们脑海就能很形象地产生 Op 双向链表的图像。

//BackStackRecord
private void doAddOp(int containerViewId, Fragment fragment, String tag, int opcmd) {
    fragment.mFragmentManager = mManager;

    if (tag != null) {
        if (fragment.mTag != null && !tag.equals(fragment.mTag)) {
            throw new IllegalStateException("Can't change tag of fragment "
                    + fragment + ": was " + fragment.mTag
                    + " now " + tag);
        }
        fragment.mTag = tag;
    }

    if (containerViewId != 0) {
        if (fragment.mFragmentId != 0 && fragment.mFragmentId != containerViewId) {
            throw new IllegalStateException("Can't change container ID of fragment "
                    + fragment + ": was " + fragment.mFragmentId
                    + " now " + containerViewId);
        }
        fragment.mContainerId = fragment.mFragmentId = containerViewId;
    }

    Op op = new Op();
    op.cmd = opcmd;
    op.fragment = fragment;
    addOp(op);
}

在本方法首先让参数 fragment 持有 FragmentManagerImpl 的引用,接着就是判断参数 tagcontainerViewId 是否有效并赋值给 fragment 的成员变量。最后 Op 对象终于出场了(此处应有掌声)。实例化了一个 OP 对象后改变了它成员变量 cmd 的值,这里是 OP_REPLACE,接着让 Op 也持有 Fragment 对象的引用,最后就是将 Op 对象作为参数调用 addOp 方法。

//BackStackRecord
void addOp(Op op) {
    if (mHead == null) {
        mHead = mTail = op;
    } else {
        op.prev = mTail;
        mTail.next = op;
        mTail = op;
    }
    op.enterAnim = mEnterAnim;
    op.exitAnim = mExitAnim;
    op.popEnterAnim = mPopEnterAnim;
    op.popExitAnim = mPopExitAnim;
    mNumOp++;
}

前面我们说过 Op 表示的是双向链表的一个结点,这里得到了证实。这个方法只是双向链表的创建及添加结点逻辑。

I-V

可以提交事务了,即调用了 BackStackRecord 对象的 commit 方法。

//BackStackRecord
public int commit() {
    return commitInternal(false);
}

int commitInternal(boolean allowStateLoss) {
    if (mCommitted) {
        throw new IllegalStateException("commit already called");
    }
    //...
    mCommitted = true;
    if (mAddToBackStack) {
        mIndex = mManager.allocBackStackIndex(this);
    } else {
        mIndex = -1;
    }
    mManager.enqueueAction(this, allowStateLoss);
    return mIndex;
}

最终调用了 commitInternal 方法,首先通过 mCommitted 判断是否已经提交过,因为默认为 false,所以这里不会抛出错误,接着最重要的逻辑就是调用了 mManager.enqueueAction(this, allowStateLoss),mManager 就是FragmentManagerImpl 对象,方法 enqueueAction 的第一个参数是 Runnable 类,但这里的 this 不是 BackStackRecord 对象么?

//BackStackRecord
final class BackStackRecord extends FragmentTransaction implements
        FragmentManager.BackStackEntry, Runnable{
        //...
}

看到了吧,BackStackRecord 实现了 Runnable,看来会有大事发生...

//FragmentManagerImpl
public void enqueueAction(Runnable action, boolean allowStateLoss) {
    //...
    synchronized (this) {
        if (mDestroyed || mHost == null) {
            throw new IllegalStateException("Activity has been destroyed");
        }
        if (mPendingActions == null) {
            mPendingActions = new ArrayList<Runnable>();
        }
        mPendingActions.add(action);
        if (mPendingActions.size() == 1) {
            mHost.getHandler().removeCallbacks(mExecCommit);
            mHost.getHandler().post(mExecCommit);
        }
    }
}

这里将 Runnable 装入了 mPendingActions 中,因为此时 mPendingActions.size() == 1true,所以最终会将 mExecCommit 成员变量压入 mHost 持有的来自 Activity 的 Handler 对象里。那么我们现在可以推断出 mExecCommit 也是 Runnable 类型,同时它会在主线程被调用。我们看看 mExecCommmit 是何方神圣。

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

原来它的作用就是为了切换到主线程然后执行它外部类即 FragmentManagerImpl 的 execPendingActions 方法而已。现在我假设这个 Runnable 对象会被马上被调用,实际可能需要排队...好,到 execPendingAcions 方法了。

//FragmentManagerImpl
public boolean execPendingActions() {
    //...
    while (true) {
        int numActions;
        
        synchronized (this) {
            if (mPendingActions == null || mPendingActions.size() == 0) {
                break;
            }
            
            numActions = mPendingActions.size();
            if (mTmpActions == null || mTmpActions.length < numActions) {
                mTmpActions = new Runnable[numActions];
            }
            mPendingActions.toArray(mTmpActions);
            mPendingActions.clear();
            mHost.getHandler().removeCallbacks(mExecCommit);
        }
        
        //...
        for (int i=0; i<numActions; i++) {
            mTmpActions[i].run();
            mTmpActions[i] = null;
        }
        //...
    }
    //...
}

本方法我们只需关注首先将 mPendingActions 里的 Runnable 对象转移到 mTmpActions 数组里,并依次调用 mTmpActions 数组保存的 Runnable 的 run 方法。我们知道这里指的就是 BackStackRecord 中的 run 方法。去看看吧

//BackStackRecord
public void run() {
    //...
    Op op = mHead;
    while (op != null) {
        switch (op.cmd) {
            //...
            case OP_REPLACE: {
                Fragment f = op.fragment;
                int containerId = f.mContainerId;
                //...
                if (f != null) {
                    f.mNextAnim = op.enterAnim;
                    mManager.addFragment(f, false);
                }
            }
            break;
            //...
        }
        op = op.next;
    }

    mManager.moveToState(mManager.mCurState, mTransition,mTransitionStyle, true);
    //...
}

这个方法其实很长的,但我们还是只要关注我们当前需要关注的逻辑就行啦。可以看到其实就是从头遍历 Op 双向链表,并通过判断 Op 对象里的 cmd 成员变量的值进行不同操作而已(其实这就是命令模式,可以看我的另一篇介绍设计模式的文章),这里我们只关注 OP_REPLACE。首先取出 Op 中保存的 Fragment 对象作为参数调用 FragmentManagerImpl 对象的 addFragment 方法,最后又通过 FragmentManagerImpl 对象的 moveToState 方法改变状态,还是一步一步来。

PS : 咳咳,下面我还有几句话要说。哈哈,我画了张思维导图,或许对照着看能更好地理解。

先看看 FragmentManagerImpl 的 addFragment 方法吧,注意这里第一个参数传入了 Fragment 对象,第二个参数传入 false

//FragmentManagerImpl
public void addFragment(Fragment fragment, boolean moveToStateNow) {
    if (mAdded == null) {
        mAdded = new ArrayList<Fragment>();
    }
    //...
    makeActive(fragment);
    if (!fragment.mDetached) {
        if (mAdded.contains(fragment)) {
            throw new IllegalStateException("Fragment already added: " + fragment);
        }
        mAdded.add(fragment);
        fragment.mAdded = true;
        fragment.mRemoving = false;
        //...
        if (moveToStateNow) {
            moveToState(fragment);
        }
    }
}

这里做了几件事:

  1. 通过 makeActive 方法将 Fragment 对象添加进 mActive 列表中。
  2. 将 Fragment 添加进 mAdded 列表中。
  3. 设置 Fragment 的一些属性。

然后到 FragmentManagerImpl 的 moveToState 方法了。我们只需关心它的第一个参数,即 mManager.mCurState,我们知道这里的 mCurState 此时已经被赋值成了 Fragment.CREATED

//FragmentManagerImpl
void moveToState(int newState, int transit, int transitStyle, boolean always) {
    //...
    mCurState = newState;
    if (mActive != null) {
        //..
        for (int i=0; i<mActive.size(); i++) {
            Fragment f = mActive.get(i);
            if (f != null) {
                moveToState(f, newState, transit, transitStyle, false);
                //...
            }
        }
        //...
    }
}

这里做了两件事

  1. 虽然 mCurState 已经是 Fragment.CREATED 了,还是被再次赋了一次 Fragment.CREATED 值。(当然不是多余,这次只不过是特殊而已啦)
  2. 和上次不同,这次 mActive 是非空的,那就遍历 mActive 取出 Fragment 作为参数并调用另一个 moveToState 方法。下面我们见识下这个方法吧(<- 大 BOSS)。方法很长,还是只关注我们需要那部分。
//FragmentManagerImpl
void moveToState(Fragment f, int newState, int transit, int transitionStyle,
        boolean keepActive) {
    //...
    if (f.mState < newState) {
        //...
        switch (f.mState) {
            case Fragment.INITIALIZING:
                //...
                f.mHost = mHost;
                f.mParentFragment = mParent;
                f.mFragmentManager = mParent != null
                        ? mParent.mChildFragmentManager : mHost.getFragmentManagerImpl();
                f.mCalled = false;
                f.onAttach(mHost.getContext());
                //...
                if (f.mParentFragment == null) {
                    mHost.onAttachFragment(f);
                }

                if (!f.mRetaining) {
                    f.performCreate(f.mSavedFragmentState);
                }
                f.mRetaining = false;
                if (f.mFromLayout) {
                    //...
                }
            //...
    }
    
    f.mState = newState;
}

首先注意这里 f.mState = Fragment.INITIALIZING(默认)newState = Fragment.CREATEDmParent = nullf.mRetaining = false(默认)f.mFromLayout = false(默认)。那么这里干了几件事。

  1. Fragment 获得了 HostCallbacks 对象的引用。
  2. Fragment 再次获得 FragmentManagerImpl 的引用。
  3. 调用了 Fragment 生命周期的第一个方法 onAttach!!
  4. 因为 f.mParentFragment == nulltrue,所以会调用 mHostonAttachFragment,进去看看
//HostCallback
@Override
public void onAttachFragment(Fragment fragment) {
    Activity.this.onAttachFragment(fragment);
}

也就说 Activity 可以通过这个方法知道被依附的 Fragment 的实例。

  1. 因为 !f.mRetainingtrue,所以会接着调用 Fragment 的 performCreate 方法
//Fragment
void performCreate(Bundle savedInstanceState) {
    //...
    onCreate(savedInstanceState);
    //...
}

这里终于调用了 Fragment 的生命周期 onCreate 方法!!

  1. 方法最后改变了 Fragment 的状态,即 f.mState = newState = Fragment.CREATED
  2. 有个容易忽略的细节就是,在每个 case 块的最后是没有 break 关键字的(可不是我忽略掉的喔,你看之前那 switch 块就有 break 关键字),也就是说只要符合条件会继续到下一个 case 块执行。

I-小结

在 Activity 的 performCreate 方法中调用了 onCreate 方法后,做了如上操作。主要做了两件最关注的事:

  1. 改变了 FragmentManagerImpl 的 mCurStateFragment.CREATED
  2. 先切换到主线程后先后调用了 Fragment 的生命周期方法 onAttachonCreate 并将 Fragment 的状态即 mState 改为了 Fragment.CREATED

II

那么就到了 Activity 的 performCreate 方法中最后调用的 performCreateCommon 方法了。

//Activity
final void performCreateCommon() {
    //...
    mFragments.dispatchActivityCreated();
    //...
}

和上面一样,相同的逻辑,那么我们可以猜到下面其实也大同小异,那就全盘托出吧。

//ActivityController
public void dispatchActivityCreated() {
    mHost.mFragmentManager.dispatchActivityCreated();
    /*一样,调用了 FragmentManagerImpl 的 dispatchActivityCreated 方法*/
}

//FragmentManagerImpl
public void dispatchActivityCreated() {
    //...
    moveToState(Fragment.ACTIVITY_CREATED, false);
    /*现在传入的状态常量是 Fragment.ACTIVITY_CREATED*/
}

//FragmentManagerImpl
void moveToState(int newState, boolean always) {
    moveToState(newState, 0, 0, always);
}

//FragmentManagerImpl
void moveToState(int newState, int transit, int transitStyle, boolean always) {
    //...
    /*mCurState 这里又被改成了 Fragment.ACTIVITY_CREATED*/
    mCurState = newState;
    if (mActive != null) {
        //...
        for (int i=0; i<mActive.size(); i++) {
            /*一样,遍历 mActive,调用 moveToState,分别将 Fragment 作为参数传入 */
            Fragment f = mActive.get(i);
            if (f != null) {
                moveToState(f, newState, transit, transitStyle, false);
                //...
            }
        }
        //...
    }
}

//FragmentManagerImpl
//方法很长,不怕,我们在代码外分析
void moveToState(Fragment f, int newState, int transit, int transitionStyle,
        boolean keepActive) {
    //...
    if (f.mState < newState) {
        //...
        switch (f.mState) {
            //...
            case Fragment.CREATED:
                if (newState > Fragment.CREATED) {
                    //...
                    if (!f.mFromLayout) {
                        ViewGroup container = null;
                        if (f.mContainerId != 0) {      
                            container = (ViewGroup)mContainer.onFindViewById(f.mContainerId);
                            if (container == null && !f.mRestored) {
                                //...
                            }
                        }
                        f.mContainer = container;
                        f.mView = f.performCreateView(f.getLayoutInflater(
                                f.mSavedFragmentState), container, f.mSavedFragmentState);
                        if (f.mView != null) {
                            //...
                            if (container != null) {
                                Animator anim = loadAnimator(f, transit, true,
                                        transitionStyle);
                                if (anim != null) {
                                    anim.setTarget(f.mView);
                                    setHWLayerAnimListenerIfAlpha(f.mView, anim);
                                    anim.start();
                                }
                                container.addView(f.mView);
                            }
                            //...
                            f.onViewCreated(f.mView, f.mSavedFragmentState);
                        }
                    }

                    f.performActivityCreated(f.mSavedFragmentState);
                    //...
                }
            //...
        }
    }
    
    f.mState = newState;
}

嗯,和我们猜的一样,最后还是调用了这个 moveToState 方法,因为现在我们的参数 newState = Fragment.ACTIVITY_CREATEDf.newState = Fragment.CREATEDf.mFromLayout = false(默认),那从代码一步一步来看这里做了几件事。

  1. 通过 ID 取出装载 Fragment 的容器并赋给 container(看到这里是不是很激动)
  2. 通过调用 f.performCreateView 获取到 View 并赋给 f.mView,那么 performCreateView 又是何方神圣?
//Fragment
View performCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    //...
    return onCreateView(inflater, container, savedInstanceState);
}

哈哈,调用了我们 Fragment 的生命周期方法 onCreateView 方法!!

  1. 然后当然是分别判断 f.mViewcontainer 是否为非空以及是否有动画,有动画的话就启动动画,可以看到,这里是属性动画。最后就将 f.mView 添加到 container 中啦。
  2. 我们下一个生命周期方法就要来啦,去看看 f.performActivityCreated
//Fragment
void performActivityCreated(Bundle savedInstanceState) {
    //...
    onActivityCreated(savedInstanceState);
    //...
}

onActivityCreated 终于出现啦,就这样,我们需要分析的生命周期方法都出来啦。

  1. 方法最后一样改变了 Fragment 的状态,这次是 f.mState = newState = Fragment.ACTIVITY_CREATED

II-小结

通过 Activity 的 performCreateCommon 方法后,做了这么两件事:

  1. 改变了 FragmentManager 的 mCruStateFragment.ACTIVITY_CREATED
  2. 接着 Fragment 的生命周期方法 onCreateView 被调用后将返回的 View 添加到指定容器中,随后就是另一个生命周期方法 onActivityCreated 方法,最后一样还会将 f.mState 改成最新的状态即 Fragment.ACTIVITY_CREATED

阶段小结

InStrumentation 对象通过 callActivityOnCreate 方法触发了 Activity 的 performCreate 后,Activity 也负责任地分别触发了 Fragment 的生命周期方法 onAttachonCreateonCreateViewonActivityCreated。经过了上面的分析,现在看这张图是不是不会觉得难记了?


其它生命周期方法逻辑没多大区别,每当 Activity 的生命周期方法被触发后它也会触发依附在它身上的 Fragment 的生命周期方法,感兴趣的朋友可以亲自去看看源码。

0x06

为了方便理解,我画了张思维导图,图片在此(超级大...)。


我再放上最开始那张类图,现在再看一遍,不知是不是印象深刻多了?

0x07

我看过很多作者写的源码解析,但这次是我第一次写源码解析,不知自己能否驾驭得当,不知能否让各位理解整个流程。如有不足,希望能在评论提出,十分感谢哈。如果觉得写得不错,不求打赏,能否稍微给我点个赞呢?

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

推荐阅读更多精彩内容

  • 近期被Fragment莫名其妙的问题困扰,所以想看看Fragment启动的过程。翻到这个大神的文章,收获很多,回头...
    用心感受世界阅读 413评论 0 0
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,510评论 25 707
  • 0 认知 Fragment官方的翻译名为:片段,表示 Activity中的行为或用户界面部分。 相比Activit...
    我是Asha阅读 2,926评论 2 25
  • 从未在傍晚上过一座山。我相信最先上峨眉的人并不是被负心人所弃后心灰意冷的决定。 这里的雾。怪石。层叠的山尖。封锁了...
    抖三抖阅读 249评论 0 0
  • 1月14日 Diary Day 日记情人节 新的一年的开始,对自己喜欢的人要有表白和计划,写在自己的日记本里,在心...
    随笔记录阅读 429评论 0 0