Fragment原理

30 阅读4分钟

基于Android Api 33

Activity的生命周期与Fragment生命周期的关联

image-2.png

示例代码

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/f1"
        android:text="Fragment 1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        />

    <fragment android:name="com.example.test_android.Fragment1"
        android:id="@+id/prefill_fragment"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        app:layout_constraintTop_toBottomOf="@id/f1"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintBottom_toTopOf="@id/content_fragment"
        />

    <FrameLayout
        android:id="@+id/content_fragment"
        android:background="#8EFDCB"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        app:layout_constraintTop_toBottomOf="@id/prefill_fragment"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        />

</androidx.constraintlayout.widget.ConstraintLayout>
import android.content.Context
import android.os.Bundle
import android.util.AttributeSet
import android.util.Log
import android.view.View
import android.widget.Button
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity

class MainActivity : FragmentActivity() {

    var f1: Button? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        Log.d("swithun-xxxx", "MainActivity onCreate")
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        f1 = findViewById(R.id.f1)

        f1()
        Log.d("swithun-xxxx", "MainActivity onCreate end")
    }

    override fun onStart() {
        Log.d("swithun-xxxx", "MainActivity onStart begin")
        super.onStart()
        Log.d("swithun-xxxx", "MainActivity onStart end")
    }

    override fun onCreateView(name: String, context: Context, attrs: AttributeSet): View? {
        Log.d("swithun-xxxx", "MainActivity onCreateView 1")
        return super.onCreateView(name, context, attrs)
    }

    override fun onCreateView(
        parent: View?,
        name: String,
        context: Context,
        attrs: AttributeSet
    ): View? {
        Log.d("swithun-xxxx", "MainActivity onCreateView 2")
        return super.onCreateView(parent, name, context, attrs)
    }

    override fun onAttachFragment(fragment: Fragment) {
        Log.d("swithun-xxxx", "MainActivity onAttachFragment")
        super.onAttachFragment(fragment)
    }

    override fun onResume() {
        Log.d("swithun-xxxx", "MainActivity onResume")
        super.onResume()
    }

    override fun onStop() {
        Log.d("swithun-xxxx", "MainActivity onResume")
        super.onStop()
    }

    override fun onDestroy() {
        Log.d("swithun-xxxx", "MainActivity onDestroy")
        super.onDestroy()
    }

    private fun f1() {
        f1?.setOnClickListener {
            val transaction = supportFragmentManager.beginTransaction();
            transaction.add(R.id.content_fragment, Fragment2())
            transaction.commit()
        }
    }
}
import android.content.Context
import android.os.Bundle
import android.util.Log
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.TextView
import androidx.fragment.app.Fragment

open class Fragment1: Fragment() {

    open val name = "fragment 1"

    override fun onAttach(context: Context) {
        Log.d("swithun-xxxx", "$name onAttach")
        super.onAttach(context)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        Log.d("swithun-xxxx", "$name onCreate")
        super.onCreate(savedInstanceState)
    }

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // 居中添加一个TextView——“hello Fragment1"
        Log.d("swithun-xxxx", "$name onCreateView")
        val view = TextView(context)
        val param = FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT)
        param.gravity = Gravity.CENTER
        view.layoutParams = param
        view.text = "hello $name"
        view.textSize = 15F
        view.gravity = Gravity.CENTER
        return view
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        Log.d("swithun-xxxx", "$name onViewCreated")
        super.onViewCreated(view, savedInstanceState)
    }

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        Log.d("swithun-xxxx", "$name onActivityCreated")
        super.onActivityCreated(savedInstanceState)
    }

    override fun onStart() {
        Log.d("swithun-xxxx", "$name onStart")
        super.onStart()
    }

    override fun onResume() {
        Log.d("swithun-xxxx", "$name onResume")
        super.onResume()
    }

    override fun onPause() {
        Log.d("swithun-xxxx", "$name onPause")
        super.onPause()
    }

    override fun onStop() {
        Log.d("swithun-xxxx", "$name onStop")
        super.onStop()
    }

    override fun onDestroyView() {
        Log.d("swithun-xxxx", "$name onDestroyView")
        super.onDestroyView()
    }

    override fun onDestroy() {
        Log.d("swithun-xxxx", "$name onDestroy")
        super.onDestroy()
    }

    override fun onDetach() {
        Log.d("swithun-xxxx", "$name onDetach")
        super.onDetach()
    }
}
class Fragment2: Fragment1() {
    override val name: String = "Fragment 2"
}

通过xml文件添加Fragment —— Fragment1

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    ...

    <fragment android:name="com.example.test_android.Fragment1"
        android:id="@+id/prefill_fragment"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        app:layout_constraintTop_toBottomOf="@id/f1"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintBottom_toTopOf="@id/content_fragment"
        />
    ...

</androidx.constraintlayout.widget.ConstraintLayout>

先从代码分析,从FragmentActivity.onCreate 开始看

  • [T-1] MainActivity.onCreate
        // MainActivity
    class MainActivity : FragmentActivity() {
        ...
        override fun onCreate(savedInstanceState: Bundle?) {
       [:0] super.onCreate(savedInstanceState)
       [:1] setContentView(R.layout.activity_main)
    

关键节点 [:0] FragmentActivity.onCreate

  • [:0] FragmentActivity.onCreate

    // androidx.fragment.app.FragmentActivity
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            ...
        [:0:1] mFragments.dispatchCreate();
        }
    
    sequenceDiagram
    autonumber
    
    participant FragmentActivity
    participant FragmentController
    
    FragmentActivity->>FragmentActivity: onCreate begin
    FragmentActivity->>FragmentController: dispatchCreate
    
    classDiagram
    
    class FragmentActivity {
        - FragmentController mFragments
    }
    class FragmentController
    
    FragmentActivity --> FragmentController: hold
    

    可以看出

    1. FragmentActivity持有FragmentController
    2. 通知FragmentController分发create事件
  • [:0:1] mFragments.dispatchCreate()

    // androidx.fragment.app.FragmentController
        public void dispatchCreate() {
       [:0:1:0] mHost.mFragmentManager.dispatchCreate();
        }
    
    sequenceDiagram
    autonumber
    
    participant FragmentActivity
    participant FragmentController
    
    FragmentActivity->>FragmentActivity: onCreate begin
    FragmentActivity->>FragmentController: dispatchCreate
    FragmentController->>FragmentManager: dispatchCreate
    
    classDiagram
    
    class FragmentActivity {
        - FragmentController mFragments
    }
    class FragmentController {
        - FragmentHostCallback<?> mHost
    }
    class FragmentManager {
        <<abstract>>
    }
    class FragmentManagerImpl
    class FragmentHostCallback {
        <<abstract>>
        - FragmentManager mFragmentManager
    }
    
    FragmentActivity --> FragmentController: hold
    FragmentController --> FragmentHostCallback: hold
    FragmentHostCallback --> FragmentManager: hold
    FragmentManagerImpl --|> FragmentManager: implements
    

    可以看出

    1. FragmentController持有FragmentHostCallback持有FragmentManger
    2. 通知FragmentManager分发create事件
  • [:0:1:0] mHost.mFragmentManager.dispatchCreate()

    // androidx.fragment.app.FragmentManager
        void dispatchCreate() {
            ...
       [:0:1:0:0] dispatchStateChange(Fragment.CREATED);
            ...
        }
    
    public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener, LifecycleOwner,
            ViewModelStoreOwner, HasDefaultViewModelProviderFactory, SavedStateRegistryOwner,
            ActivityResultCaller {
    
        static final int INITIALIZING = -1;          // Not yet attached.
        static final int ATTACHED = 0;               // Attached to the host.
        static final int CREATED = 1;                // Created.
        static final int VIEW_CREATED = 2;           // View Created.
        static final int AWAITING_EXIT_EFFECTS = 3;  // Downward state, awaiting exit effects
        static final int ACTIVITY_CREATED = 4;       // Fully created, not started.
        static final int STARTED = 5;                // Created and started, not resumed.
        static final int AWAITING_ENTER_EFFECTS = 6; // Upward state, awaiting enter effects
        static final int RESUMED = 7;                // Created started and resumed.
    
    sequenceDiagram
    autonumber
    
    participant FragmentActivity
    participant FragmentController
    participant FragmentManager
    
    FragmentActivity->>FragmentActivity: onCreate begin
    FragmentActivity->>FragmentController: dispatchCreate
    FragmentController->>FragmentManager: dispatchCreate
    FragmentManager->>FragmentManager: dispatchStateChange
    

    可以看出

    1. FragmentManager内部分发Fragment.CREATED事件——Attached to the host
  • [:0:1:0:0] dispatchStateChange(Fragment.CREATED)

    // androidx.fragment.app.FragmentManager
        private void dispatchStateChange(int nextState) {
            ...
           [:0:1:0:0:0] mFragmentStore.dispatchStateChange(nextState);
           [:0:1:0:0:1] moveToState(nextState, false);
           ...
    }
    
    public abstract class FragmentManager implements FragmentResultOwner {
        ...
        private final FragmentStore mFragmentStore = new FragmentStore();
    
    sequenceDiagram
    autonumber
    
    participant FragmentActivity
    participant FragmentController
    participant FragmentManager
    participant FragmentStore
    
    FragmentActivity->>FragmentActivity: onCreate begin
    FragmentActivity->>FragmentController: dispatchCreate
    FragmentController->>FragmentManager: dispatchCreate
    FragmentManager->>FragmentManager: dispatchStateChange
    FragmentManager->>FragmentStore: dispatchStateChange
    
    classDiagram
    
    class FragmentActivity {
        - FragmentController mFragments
    }
    class FragmentController {
        - FragmentHostCallback<?> mHost
    }
    class FragmentManager {
        <<abstract>>
        FragmentStore mFragmentStore
    }
    class FragmentManagerImpl
    class FragmentHostCallback {
        <<abstract>>
        - FragmentManager mFragmentManager
    }
    class FragmentStore
    
    FragmentActivity --> FragmentController: hold
    FragmentController --> FragmentHostCallback: hold
    FragmentHostCallback --> FragmentManager: hold
    FragmentManagerImpl --|> FragmentManager: implements
    FragmentManager --> FragmentStore: hold
    

    可以看出

    1. FragmentManager持有一个FragmentStore
    2. FragmentStore分发收到的状态nextState——Fragment.CREATED
  • [:0:1:0:0:0] mFragmentStore.dispatchStateChange(nextState)

    // androidx.fragment.app.FragmentStore
        void dispatchStateChange(int state) {
            for (FragmentStateManager fragmentStateManager : mActive.values()) {
                if (fragmentStateManager != null) {
     [:0:1:0:0:0:0] fragmentStateManager.setFragmentManagerState(state);
                }
            }
        }
    

    mActive是存储FragmentStateManagerMap:⬇️

    // androidx.fragment.app.FragmentStore
    class FragmentStore {
        ...
        private final HashMap<String, FragmentStateManager> mActive = new HashMap<>();
    
    sequenceDiagram
    autonumber
    
    participant FragmentActivity
    participant FragmentController
    participant FragmentManager
    participant FragmentStore
    participant FragmentStateManager
    
    FragmentActivity->>FragmentActivity: onCreate begin
    FragmentActivity->>FragmentController: dispatchCreate
    FragmentController->>FragmentManager: dispatchCreate
    FragmentManager->>FragmentManager: dispatchStateChange
    FragmentManager->>FragmentStore: dispatchStateChange
    FragmentStore->>FragmentStateManager: setFragmentManagerState
    
    classDiagram
    
    class FragmentActivity {
        - FragmentController mFragments
    }
    class FragmentController {
        - FragmentHostCallback<?> mHost
    }
    class FragmentManager {
        <<abstract>>
        FragmentStore mFragmentStore
    }
    class FragmentManagerImpl
    class FragmentHostCallback {
        <<abstract>>
        - FragmentManager mFragmentManager
    }
    class FragmentStore {
        HashMap「String, FragmentStateManager」 mActive
    }
    class FragmentStateManager
    
    FragmentActivity --> FragmentController: hold
    FragmentController --> FragmentHostCallback: hold
    FragmentHostCallback --> FragmentManager: hold
    FragmentManagerImpl --|> FragmentManager: implements
    FragmentManager --> FragmentStore: hold
    FragmentStore "1" --> "n" FragmentStateManager: hold
    

    可以看出

    1. FragmentStore持有n个FragmentStateManager
    2. FragmentManager将收到的状态分发给每一个FragmentStateManager

    [总结]: 由于FragmentActivity此时尚未setContentView,所以FragmentManger管理的Fragment数量实际上为0,mActive自然为0。但是我们仍然继续看下如果不为0会继续做什么。

  • [:0:1:0:0:0:0] fragmentStateManager.setFragmentManagerState(state)

    // androidx.fragment.app.FragmentStateManager
        void setFragmentManagerState(int state) {
            mFragmentManagerState = state;
        }
    
    // androidx.fragment.app.FragmentStateManager
    class FragmentStateManager {
        ...
        private final Fragment mFragment;
        private int mFragmentManagerState = Fragment.INITIALIZING;
    
    classDiagram
    
    class FragmentActivity {
        - FragmentController mFragments
    }
    class FragmentController {
        - FragmentHostCallback<?> mHost
    }
    class FragmentManager {
        <<abstract>>
        FragmentStore mFragmentStore
    }
    class FragmentManagerImpl
    class FragmentHostCallback {
        <<abstract>>
        - FragmentManager mFragmentManager
    }
    class FragmentStore {
        HashMap「String, FragmentStateManager」 mActive
    }
    class FragmentStateManager {
        Fragment mFragment
        int mFragmentManagerState
    }
    class Fragment
    
    FragmentActivity --> FragmentController: hold
    FragmentController --> FragmentHostCallback: hold
    FragmentHostCallback --> FragmentManager: hold
    FragmentManagerImpl --|> FragmentManager: implements
    FragmentManager --> FragmentStore: hold
    FragmentStore "1" --> "n" FragmentStateManager: hold
    FragmentStateManager --> Fragment: hold
    

    可以看出

    1. FragmentStateManager 1:1 持有Fragment
    2. FragmentStateManaget持有变量mFragmentManagerState——所属的FragmentManager的状态

    至此,FragmentActivityCREATE状态通知到FragmentManager进而通知到管理的每个FragmentStateManager——但是此时Fragment尚未更新。

    [总结]: (只关心重要的FragmentActivity,FragmentManager,Fragment

    sequenceDiagram
    autonumber
    
    participant FragmentActivity
    participant FragmentManager
    participant Fragment
    
    FragmentActivity->>FragmentActivity: onCreate begin
    FragmentActivity->>FragmentManager: dispatchCreate() 分发CREATE
    
  • [:0:1:0:0:1] moveToState(nextState, false);

    // androidx.fragment.app.FragmentManager
        void moveToState(int newState, boolean always) {
            ...
                mFragmentStore.moveToExpectedState();
            ...
    
    sequenceDiagram
    autonumber
    
    participant FragmentActivity
    participant FragmentController
    participant FragmentManager
    participant FragmentStore
    
    FragmentActivity->>FragmentActivity: onCreate begin
    FragmentActivity->>FragmentController: dispatchCreate
    FragmentController->>FragmentManager: dispatchCreate
    FragmentManager->>FragmentManager: dispatchStateChange
    FragmentManager->>FragmentStore: dispatchStateChange
    FragmentManager->>FragmentManager: moveToState
    

    [:0:1:0:0:0:0]只是将用来管理FragmentFragmentStateManager的状态更新了,这里才是真正更新Fragment的状态——但是此时FragmentManager管理的Fragment数量实际上为0,所以这里先不继续看,后续流程下面[:1:0:0:1]会继续讲到。

关键节点 [:1] setContentView(R.layout.activity_main)

  • [:1] setContentView(R.layout.activity_main) 执行[:0] super.onCreate(savedInstanceState)之后,setContentView

    // androidx.activity.ComponentActivity
        @Override
        public void setContentView(@LayoutRes int layoutResID) {
            ...
        [:1:0] super.setContentView(layoutResID);
        }
    
    sequenceDiagram
    autonumber
    
    participant FragmentActivity
    participant FragmentController
    participant Activity
    
    FragmentActivity->>FragmentActivity: onCreate begin
    FragmentActivity->>FragmentController: dispatchCreate
    FragmentActivity->>Activity: setContentView
    
    classDiagram
    
    class FragmentActivity {
        - FragmentController mFragments
    }
    class FragmentController
    class Activity
    
    FragmentActivity --> FragmentController: hold
    FragmentActivity --|> Activity
    
  • [:1:0] super.setContentView(layoutResID); ComponentActivity调用父类Activity.setContentView

    // android.app.Activity
        public void setContentView(@LayoutRes int layoutResID) {
       [:1:0:0] getWindow().setContentView(layoutResID);
       ...
    
    sequenceDiagram
    autonumber
    
    participant FragmentActivity
    participant FragmentController
    participant Activity
    participant Window
    
    FragmentActivity->>FragmentActivity: onCreate begin
    FragmentActivity->>FragmentController: dispatchCreate
    FragmentActivity->>Activity: setContentView
    Activity->>Window: setContentView
    
    classDiagram
    
    class FragmentActivity {
        - FragmentController mFragments
    }
    class FragmentController
    class Activity {
        - Window mWindow
    }
    
    FragmentActivity --> FragmentController: hold
    FragmentActivity --|> Activity
    Activity --> Window: hold
    
  • [:1:0:0] getWindow().setContentView(layoutResID); Window.setContentView

    // android.view.Window
        public abstract void setContentView(@LayoutRes int layoutResID);
    

    继续-跳过细节 根据传入的layout ResId 初始化 view

    // com.android.internal.policy.PhoneWindow
        @Override
        public void setContentView(int layoutResID) {
            ...
            [...]    mLayoutInflater.inflate(layoutResID, mContentParent);
            ...
    
    sequenceDiagram
    autonumber
    
    participant FragmentActivity
    participant FragmentController
    participant Activity
    participant PhoneWindow
    participant LayoutInflater
    
    FragmentActivity->>FragmentActivity: onCreate begin
    FragmentActivity->>FragmentController: dispatchCreate
    FragmentActivity->>Activity: setContentView
    Activity->>PhoneWindow: setContentView
    PhoneWindow->>LayoutInflater: inflate
    
    classDiagram
    
    class FragmentActivity {
        - FragmentController mFragments
    }
    class FragmentController
    class Activity {
        - Window mWindow
    }
    class PhoneWindow {
        - LayoutInflater mLayoutInflater
    }
    class LayoutInflater
    
    FragmentActivity --> FragmentController: hold
    FragmentActivity --|> Activity
    Activity --> Window: hold
    PhoneWindow --|> Window
    PhoneWindow --> LayoutInflater: hold
    

    mContentParentPhoneWindow的根View,下面会根据layoutResID构造View并add到mContentParent
    继续-跳过细节 根据传入的layout ResId 初始化 view

    // android.view.LayoutInflater
        public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) {
            return inflate(resource, root, root != null);
    
    // android.view.LayoutInflater
        public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) {
            [...] return inflate(parser, root, attachToRoot);
            ...
        }
    

    attachToRoot为true(root != null)

        // android.view.LayoutInflater
        public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {
            synchronized (mConstructorArgs) {
                ...
                    advanceToRootNode(parser); // 让parser移动到下一个要解析的"结点"
                    final String name = parser.getName(); // 获取结点名字
                    ...
                        // 根据名字构造xml的根view
                        final View temp = createViewFromTag(root, name, inflaterContext, attrs);
                    ...
                        // 继续递归构造xml根view的子view,并addView到根view
                        rInflateChildren(parser, temp, attrs, true);
    

    根据xml parser构造Viewtempxml的根标签代表的view,根据activity_main.xml xml-1 ⬇️

    <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.ConstraintLayout     ...>
        <Button..>
    
        <fragment android:name="com.example.test_android.Fragment1"...>
    
        <FrameLayout
            android:id="@+id/content_fragment"...>
    
    </androidx.constraintlayout.widget.ConstraintLayout>
    

    name则为根标签androidx.constraintlayout.widget.ConstraintLayout
    temp相应的则是androidx.constraintlayout.widget.ConstraintLayout
    下面rInflateChildren则是继续递归的构造ConstraintLayout中的子view。(开头的r代表的是Recursive--递归)

    // android.view.LayoutInflater
        final void rInflateChildren(XmlPullParser parser, View parent, AttributeSet attrs,
                boolean finishInflate) throws XmlPullParserException, IOException {
            rInflate(parser, parent, parent.getContext(), attrs, finishInflate);
    
    // android.view.LayoutInflater
        void rInflate(XmlPullParser parser, View parent, Context context,
                AttributeSet attrs, boolean finishInflate) throws XmlPullParserException, IOException {
            ...
                while (((type = parser.next()) != XmlPullParser.END_TAG ||
                    ...
                    final View view = createViewFromTag(parent, name, context, attrs);
            ...
    

    rInflate: 继续递归构造temp的子view parser.next: 不断的获取下一个要解析的标签,根据xml-1,会解析到 <fragment标签——通过createViewFromTag构造Fragment

    // android.view.LayoutInflater
        private View createViewFromTag(View parent, String name, Context context, AttributeSet attrs) {
            return createViewFromTag(parent, name, context, attrs, false);
    
    // android.view.LayoutInflater
        View createViewFromTag(View parent, String name, Context context, AttributeSet attrs,
            ...
                View view = tryCreateView(parent, name, context, attrs);
            ...
    

    构造fragment view

    // android.view.LayoutInflater
        public final View tryCreateView(@Nullable View parent, @NonNull String name,
            ...
                view = mPrivateFactory.onCreateView(parent, name, context, attrs);
            ...
    
    // android.view.LayoutInflater
        private Factory2 mPrivateFactory;
    
    sequenceDiagram
    autonumber
    
    participant FragmentActivity
    participant FragmentController
    participant Activity
    participant PhoneWindow
    participant LayoutInflater
    participant LayoutInflater-Factory2
    
    FragmentActivity->>FragmentActivity: onCreate begin
    FragmentActivity->>FragmentController: dispatchCreate
    FragmentActivity->>Activity: setContentView
    Activity->>PhoneWindow: setContentView
    PhoneWindow->>LayoutInflater: inflate
    LayoutInflater->>LayoutInflater-Factory2: onCreateView
    
    classDiagram
    
    class FragmentActivity {
        - FragmentController mFragments
    }
    class FragmentController
    class Activity {
        - Window mWindow
    }
    class PhoneWindow {
        - LayoutInflater mLayoutInflater
    }
    class LayoutInflater
    class `LayoutInflater-Factory2`
    
    FragmentActivity --> FragmentController: hold
    FragmentActivity --|> Activity
    Activity --> Window: hold
    PhoneWindow --|> Window
    PhoneWindow --> LayoutInflater: hold
    Activity --|> `LayoutInflater-Factory2`
    LayoutInflater --> `LayoutInflater-Factory2`: hold
    

    mPrivateFactory实际上是我们写的的MainActivity,所以继续会走到MainActivity.onCreateView

    // androidx.fragment.app.FragmentActivity
        public View onCreateView(@Nullable View parent, @NonNull String name, @NonNull Context context,
                @NonNull AttributeSet attrs) {
            final View v = dispatchFragmentsOnCreateView(parent, name, context, attrs);
            if (v == null) {
                return super.onCreateView(parent, name, context, attrs);
            }
            return v;
        }
    

    @param View parent: xml的根布局ConstraintLayout @param String name: fragment,也就是xml-1中的fragment标签 dispatchFragmentsOnCreateView(: 会先尝试通过该方法处理fragment标签对应的View,如果有返回结果则跳过if (v == null)中的逻辑,我们这里nameframgment,所以不应该返回null。

    sequenceDiagram
    autonumber
    
    participant FragmentActivity
    participant FragmentController
    participant Activity
    participant PhoneWindow
    participant LayoutInflater
    participant LayoutInflater-Factory2
    
    FragmentActivity->>FragmentActivity: onCreate begin
    FragmentActivity->>FragmentController: dispatchCreate
    FragmentActivity->>Activity: setContentView
    Activity->>PhoneWindow: setContentView
    PhoneWindow->>LayoutInflater: inflate
    LayoutInflater->>LayoutInflater-Factory2: onCreateView
    LayoutInflater-Factory2->>FragmentActivity: onCreateView
    
    classDiagram
    
    class FragmentActivity {
        - FragmentController mFragments
    }
    class FragmentController
    class Activity {
        - Window mWindow
    }
    class PhoneWindow {
        - LayoutInflater mLayoutInflater
    }
    class LayoutInflater
    class `LayoutInflater-Factory2`
    
    FragmentActivity --> FragmentController: hold
    FragmentActivity --|> Activity
    Activity --> Window: hold
    PhoneWindow --|> Window
    PhoneWindow --> LayoutInflater: hold
    Activity --|> `LayoutInflater-Factory2`
    LayoutInflater --> `LayoutInflater-Factory2`: hold
    
    // androidx.fragment.app.FragmentActivity
        @Nullable
        final View dispatchFragmentsOnCreateView(@Nullable View parent, @NonNull String name,
                @NonNull Context context, @NonNull AttributeSet attrs) {
            return mFragments.onCreateView(parent, name, context, attrs);
    
    sequenceDiagram
    autonumber
    
    participant FragmentActivity
    participant FragmentController
    participant Activity
    participant PhoneWindow
    participant LayoutInflater
    participant LayoutInflater-Factory2
    
    FragmentActivity->>FragmentActivity: onCreate begin
    FragmentActivity->>FragmentController: dispatchCreate
    FragmentActivity->>Activity: setContentView
    Activity->>PhoneWindow: setContentView
    PhoneWindow->>LayoutInflater: inflate
    LayoutInflater->>LayoutInflater-Factory2: onCreateView
    LayoutInflater-Factory2->>FragmentActivity: onCreateView
    FragmentActivity->>FragmentController: onCreateView
    
    // androidx.fragment.app.FragmentController
        public View onCreateView(@Nullable View parent, @NonNull String name, @NonNull Context context,
                @NonNull AttributeSet attrs) {
            return mHost.mFragmentManager.getLayoutInflaterFactory()
                    .onCreateView(parent, name, context, attrs);
        }
    
    sequenceDiagram
    autonumber
    
    participant FragmentActivity
    participant FragmentController
    participant Activity
    participant PhoneWindow
    participant LayoutInflater
    participant LayoutInflater-Factory2
    participant FragmentLayoutInflaterFactory
    
    FragmentActivity->>FragmentActivity: onCreate begin
    FragmentActivity->>FragmentController: dispatchCreate
    FragmentActivity->>Activity: setContentView
    Activity->>PhoneWindow: setContentView
    PhoneWindow->>LayoutInflater: inflate
    LayoutInflater->>LayoutInflater-Factory2: onCreateView
    LayoutInflater-Factory2->>FragmentActivity: onCreateView
    FragmentActivity->>FragmentController: onCreateView
    FragmentController->>FragmentLayoutInflaterFactory: onCreateView
    
    classDiagram
    
    class FragmentActivity {
        - FragmentController mFragments
    }
    class FragmentController {
        FragmentHostCallback<?> mHost
    }
    class Activity {
        - Window mWindow
    }
    class PhoneWindow {
        - LayoutInflater mLayoutInflater
    }
    class LayoutInflater
    class `LayoutInflater-Factory2`
    class FragmentManager {
        FragmentLayoutInflaterFactory mLayoutInflaterFactory
    }
    class FragmentHostCallback {
        <<abstract>>
        FragmentManager mFragmentManager
    }
    class FragmentLayoutInflaterFactory
    
    FragmentActivity --> FragmentController: hold
    FragmentActivity --|> Activity
    Activity --> Window: hold
    PhoneWindow --|> Window
    PhoneWindow --> LayoutInflater: hold
    Activity --|> `LayoutInflater-Factory2`
    LayoutInflater --> `LayoutInflater-Factory2`: hold
    FragmentController --> FragmentHostCallback: hold
    FragmentHostCallback --> FragmentManager: hold
    FragmentManager --> FragmentLayoutInflaterFactory: hold
    

    return FragmentActivity.dispatchFragmentsOnCreateView \rightarrow return FragmentController.onCreateView \rightarrow return FragmentLayoutInflaterFactory.onCreateView

    // androidx.fragment.app.FragmentLayoutInflaterFactory
        public View onCreateView(@Nullable final View parent, @NonNull String name,
            ...
                // new Fragment
                fragment = mFragmentManager.getFragmentFactory().instantiate(
                context.getClassLoader(), fname);
                // fragment 的属性设置 begin
                fragment.mFromLayout = true;
                fragment.mFragmentId = id != 0 ? id : containerId;
                fragment.mContainerId = containerId;
                fragment.mTag = tag;
                fragment.mInLayout = true;
                fragment.mFragmentManager = mFragmentManager;
                fragment.mHost = mFragmentManager.getHost();
                fragment.onInflate(mFragmentManager.getHost().getContext(), attrs,
                        fragment.mSavedFragmentState);
                // fragment 的属性设置 end
    
                // 添加到mFragmentManager中,同时返回 持有Fragment的FragmentStateManager
                fragmentStateManager = mFragmentManager.addFragment(fragment);
                // 此时Fragment这个壳已经初始化,但是Fragment.mView实际上还没有构造
            ...
            // 通过FragmentStateManager更新他持有的一对一的Fragment的State
       [:1:0:0:1] fragmentStateManager.moveToExpectedState();
            // 确保走到这行代码是Fragment已经构造好view
       [B2] fragmentStateManager.ensureInflatedView();
    
    sequenceDiagram
    autonumber
    
    participant FragmentActivity
    participant FragmentController
    participant Activity
    participant PhoneWindow
    participant LayoutInflater
    participant LayoutInflater-Factory2
    participant FragmentLayoutInflaterFactory
    participant Fragment
    participant FragmentStateManager
    
    FragmentActivity->>FragmentActivity: onCreate begin
    FragmentActivity->>FragmentController: dispatchCreate
    FragmentActivity->>Activity: setContentView
    Activity->>PhoneWindow: setContentView
    PhoneWindow->>LayoutInflater: inflate
    LayoutInflater->>LayoutInflater-Factory2: onCreateView
    LayoutInflater-Factory2->>FragmentActivity: onCreateView
    FragmentActivity->>FragmentController: onCreateView
    FragmentController->>FragmentLayoutInflaterFactory: onCreateView
    FragmentLayoutInflaterFactory->>Fragment: new
    FragmentLayoutInflaterFactory->>FragmentManager: addFragment
    FragmentManager->>FragmentLayoutInflaterFactory: addFragment return FragmentStateManager
    FragmentLayoutInflaterFactory->>FragmentStateManager: moveToExpectedState
    
    classDiagram
    
    class FragmentActivity {
        - FragmentController mFragments
    }
    class FragmentController {
        FragmentHostCallback<?> mHost
    }
    class Activity {
        - Window mWindow
    }
    class PhoneWindow {
        - LayoutInflater mLayoutInflater
    }
    class LayoutInflater
    class `LayoutInflater-Factory2`
    class FragmentManager {
        FragmentLayoutInflaterFactory mLayoutInflaterFactory
    }
    class FragmentHostCallback {
        <<abstract>>
        FragmentManager mFragmentManager
    }
    class FragmentLayoutInflaterFactory {
        FragmentManager mFragmentManager
    }
    
    FragmentActivity --> FragmentController: hold
    FragmentActivity --|> Activity
    Activity --> Window: hold
    PhoneWindow --|> Window
    PhoneWindow --> LayoutInflater: hold
    Activity --|> `LayoutInflater-Factory2`
    LayoutInflater --> `LayoutInflater-Factory2`: hold
    FragmentController --> FragmentHostCallback: hold
    FragmentHostCallback --> FragmentManager: hold
    FragmentManager --> FragmentLayoutInflaterFactory: hold
    FragmentLayoutInflaterFactory --> FragmentManager: ref
    
    • fragmentStateManager = mFragmentManager.addFragment(fragment);: 将新建的Fragment添加到FragmentManager中进行管理。
  • [:1:0:0:1] fragmentStateManager.moveToExpectedState(); 通过FragmentStateManager更新他持有的一对一的Fragment的State

    // androidx.fragment.app.FragmentStateManager
        void moveToExpectedState() {
            ...
                int newState;
         [:1:0:0:1:0] while ((newState = computeExpectedState()) != mFragment.mState) {
                    if (newState > mFragment.mState) {
                        // Moving upward
                        int nextStep = mFragment.mState + 1;
                        switch (nextStep) {
                            case Fragment.ATTACHED:
                         [:1:0:0:1:1] attach();
                            case Fragment.CREATED:
                         [:1:0:0:1:2] create();
                                break;
                            case Fragment.VIEW_CREATED:
                         [:1:0:0:1:3] ensureInflatedView();
                         [:1:0:0:1:4] createView();
                                break;
    
  • [:1:0:0:1:0] while ((newState = computeExpectedState()) != mFragment.mState) {

    • computeExpectedState(): 根据FragmentManager等等计算mFragment应该达到的状态,先不看这里的复杂计算,但是最终的结果是2,对应Fragment.VIEW_CREATED,即Fragment应该进行到构造好View的状态
    • while: mFragment不断切换到下一个状态,直到达到目标状态——VIEW_CREATED
    • mFragment.mState: 当前mFragment.mStateINITIALIZING,则表示会依次执行FragmentManager.attach()FragmentManager.create()FragmentManager.createView()
        static final int INITIALIZING = -1;          // Not yet attached.
        static final int ATTACHED = 0;               // Attached to the host.
        static final int CREATED = 1;                // Created.
        static final int VIEW_CREATED = 2;           // View Created.
        static final int AWAITING_EXIT_EFFECTS = 3;  // Downward state, awaiting exit effects
        static final int ACTIVITY_CREATED = 4;       // Fully created, not started.
        static final int STARTED = 5;                // Created and started, not resumed.
        static final int AWAITING_ENTER_EFFECTS = 6; // Upward state, awaiting enter effects
        static final int RESUMED = 7;                // Created started and resumed.
    
  • [:1:0:0:1:1] attach();

    // androidx.fragment.app.FragmentStateManager
        void attach() {
            ....
    [:1:0:0:1:1:0] mFragment.performAttach();
            mDispatcher.dispatchOnFragmentAttached(mFragment, false);
        }
    
    sequenceDiagram
    autonumber
    
    participant FragmentActivity
    participant FragmentController
    participant Activity
    participant PhoneWindow
    participant LayoutInflater
    participant LayoutInflater-Factory2
    participant FragmentLayoutInflaterFactory
    participant Fragment
    participant FragmentStateManager
    
    FragmentActivity->>FragmentActivity: onCreate begin
    FragmentActivity->>FragmentController: dispatchCreate
    FragmentActivity->>Activity: setContentView
    Activity->>PhoneWindow: setContentView
    PhoneWindow->>LayoutInflater: inflate
    LayoutInflater->>LayoutInflater-Factory2: onCreateView
    LayoutInflater-Factory2->>FragmentActivity: onCreateView
    FragmentActivity->>FragmentController: onCreateView
    FragmentController->>FragmentLayoutInflaterFactory: onCreateView
    FragmentLayoutInflaterFactory->>Fragment: new
    FragmentLayoutInflaterFactory->>FragmentManager: addFragment
    FragmentManager->>FragmentLayoutInflaterFactory: addFragment return FragmentStateManager
    FragmentLayoutInflaterFactory->>FragmentStateManager: moveToExpectedState
    FragmentStateManager->>Fragment: performAttach
    
  • [:1:0:0:1:1:0] mFragment.performAttach()

    // androidx.fragment.app.Fragment
        void performAttach() {
            ...
            mState = ATTACHED;
            onAttach(mHost.getContext());
            ...
            mChildFragmentManager.dispatchAttach();
        }
    
    • mState = ATTACHED: 更新Fragment状态为ATTACHED
    // androidx.fragment.app.Fragment
        public void onAttach(@NonNull Context context) {
            mCalled = true;
            final Activity hostActivity = mHost == null ? null : mHost.getActivity();
            if (hostActivity != null) {
                mCalled = false;
                onAttach(hostActivity);
            }
        }
    
    // androidx.fragment.app.Fragment
        public void onAttach(@NonNull Activity activity) {
            mCalled = true;
        }
    

至此,Fragment的状态由INITIALIZING切换到ATTACHED切换到CREATED切换到VIEW_CREATED,关键方法是B1-fragmentStateManager.moveToExpectedState,不断的将FragmentStateManager所管理的所有Fragment推动到应该达到的状态。

sequenceDiagram
autonumber

participant FragmentActivity
participant FragmentManager
participant Fragment

activate FragmentActivity
FragmentActivity->>FragmentActivity: onCreate begin
FragmentActivity->>FragmentManager: dispatchCreate() 分发CREATE
FragmentActivity->>FragmentActivity: setContentView begin
FragmentActivity->>FragmentActivity: onCreateView
FragmentActivity->>FragmentManager: moveToExpectedState
FragmentManager->>Fragment: performAttach
Fragment->>Fragment: onAttach
FragmentManager->>Fragment: performCreate
FragmentManager->>Fragment: performCreateView

FragmentActivity->>FragmentActivity: onCreate end 
deactivate FragmentActivity

FragmentActivity->>FragmentActivity: onStart

以上以Create为例,了解了FragmentActivity的状态对Fragment的状态影响以及FragmentActivity, FragmentController, FragmentManager, FragmentStateManager, Fragment中间的关系。

MainActivity onCreate
MainActivity onCreateView 2
MainActivity onCreateView 1
MainActivity onCreateView 2
MainActivity onCreateView 1
MainActivity onCreateView 2
MainActivity onCreateView 1
MainActivity onCreateView 2
MainActivity onCreateView 1
MainActivity onCreateView 2
MainActivity onCreateView 1
MainActivity onCreateView 2
fragment 1 onAttach
MainActivity onAttachFragment
fragment 1 onCreate
fragment 1 onCreateView
fragment 1 onViewCreated
MainActivity onCreateView 2
MainActivity onCreateView 1
MainActivity onCreate end
MainActivity onStart begin
fragment 1 onActivityCreated
fragment 1 onStart
MainActivity onStart end
MainActivity onResume
fragment 1 onResumek

简单总结:

Activity 生命周期回调Fragment 生命周期回调
onCreate- onAttach
- onCreate
- onCreateView
- onViewCreated
onStart- onActivityCreated
- onStart
onResume- onResume

总结

总结以上,FragmentActivity onCreate 时将 Create 事件 1:通知:1\xrightarrow{1:通知:1} FragmentController 1:通知:1\xrightarrow{1:通知:1} FragmentManager 1:通知:n\xrightarrow{1:通知:n} 持有的每个 FragmentStateManager 1:通知:1\xrightarrow{1:通知:1} Fragment

代码中动态添加Fragment

// MainActivity
    private fun f1() {
        f1?.setOnClickListener {
       [:2] val transaction = supportFragmentManager.beginTransaction()
       [:3] transaction.add(R.id.content_fragment, Fragment2())
       [:4] transaction.commit()
        }
    }
  • [:2] val transaction = supportFragmentManager.beginTransaction()

    // androidx.fragment.app.FragmentManager
        public FragmentTransaction beginTransaction() {
            return new BackStackRecord(this);
        }
    
    sequenceDiagram
    autonumber
    
    participant MainActivity
    participant FragmentManager
    participant FragmentTransaction
    participant BackStackRecord
    
    MainActivity ->> FragmentManager: beginTransaction
    FragmentManager ->> FragmentTransaction: new
    FragmentManager ->> BackStackRecord: new
    FragmentManager ->> MainActivity: return (FragmentTransaction)BackStackRecord
    
    classDiagram
    class FragmentTransaction
    class BackStackRecord
    class FragmentManager
    class `FragmentManager-BackStackEntry`
    class `FragmentManager-OpGenerator`
    
    BackStackRecord --|> FragmentTransaction: extends
    BackStackRecord --|> `FragmentManager-BackStackEntry`: impl
    BackStackRecord --|>` FragmentManager-OpGenerator`: impl
    FragmentManager --> BackStackRecord: create
    
  • [:3] transaction.add(R.id.content_fragment, Fragment2())

    // androidx.fragment.app.FragmentTransaction
        public FragmentTransaction add(@IdRes int containerViewId, @NonNull Fragment fragment) {
       [:3:0] doAddOp(containerViewId, fragment, null, OP_ADD);
            return this;
        }
    
    sequenceDiagram
    autonumber
    
    participant MainActivity
    participant FragmentManager
    participant FragmentTransaction
    participant BackStackRecord
    
    MainActivity ->> FragmentManager: beginTransaction
    FragmentManager ->> FragmentTransaction: new
    FragmentManager ->> BackStackRecord: new
    FragmentManager ->> MainActivity: return (FragmentTransaction)BackStackRecord
    MainActivity ->> FragmentTransaction: add
    

    其中OP_ADD⬇️ = 1

    // androidx.fragment.app.FragmentTransaction
        static final int OP_NULL = 0;
        static final int OP_ADD = 1;
        static final int OP_REPLACE = 2;
        static final int OP_REMOVE = 3;
        static final int OP_HIDE = 4;
        static final int OP_SHOW = 5;
        static final int OP_DETACH = 6;
        static final int OP_ATTACH = 7;
        static final int OP_SET_PRIMARY_NAV = 8;
        static final int OP_UNSET_PRIMARY_NAV = 9;
        static final int OP_SET_MAX_LIFECYCLE = 10;
    
  • [:3:0] doAddOp(containerViewId, fragment, null, OP_ADD)

    // androidx.fragment.app.FragmentTransaction
        void doAddOp(int containerViewId, Fragment fragment, @Nullable String tag, int opcmd) {
            ...
       [:3:0:1] addOp(new Op(opcmd, fragment));
        }
    
  • [:3:0:1] addOp(new Op(opcmd, fragment))

    // androidx.fragment.app.FragmentTransaction
        void addOp(Op op) {
            mOps.add(op);
            ...
        }
    
    // androidx.fragment.app.FragmentTransaction
        ArrayList<Op> mOps = new ArrayList<>();
    
    classDiagram
    class FragmentTransaction {
        mOps: ArrayList<OP>
    }
    class BackStackRecord
    class FragmentManager
    class `FragmentManager-BackStackEntry`
    class `FragmentManager-OpGenerator`
    class `FragmentTransaction-Op` {
        mCmd: int
        mFragment: Fragment
    }
    
    BackStackRecord --|> FragmentTransaction: extends
    BackStackRecord --|> `FragmentManager-BackStackEntry`: impl
    BackStackRecord --|> `FragmentManager-OpGenerator`: impl
    FragmentManager --> BackStackRecord: create
    FragmentTransaction --> `FragmentTransaction-Op`: holds
    

    FragmentTransaction 中有一个 Op list记录我们添加的操作——OP_ADD

  • [:4] transaction.commit()

    // androidx.fragment.app.FragmentTransaction
        public abstract int commit();
    
    sequenceDiagram
    autonumber
    
    participant MainActivity
    participant FragmentManager
    participant FragmentTransaction
    participant BackStackRecord
    
    MainActivity ->> FragmentManager: beginTransaction
    FragmentManager ->> FragmentTransaction: new
    FragmentManager ->> BackStackRecord: new
    FragmentManager ->> MainActivity: return (FragmentTransaction)BackStackRecord
    MainActivity ->> FragmentTransaction: add
    MainActivity ->> FragmentTransaction: commit
    
    // androidx.fragment.app.BackStackRecord
        @Override
        public int commit() {
            return commitInternal(false);
        }
    
        // androidx.fragment.app.BackStackRecord
        int commitInternal(boolean allowStateLoss) {
            ...
        [:4:0] mManager.enqueueAction(this, allowStateLoss);
            ...
        }
    
    sequenceDiagram
    autonumber
    
    participant MainActivity
    participant FragmentManager
    participant FragmentTransaction
    participant BackStackRecord
    
    MainActivity ->> FragmentManager: beginTransaction
    FragmentManager ->> FragmentTransaction: new
    FragmentManager ->> BackStackRecord: new
    FragmentManager ->> MainActivity: return (FragmentTransaction)BackStackRecord
    MainActivity ->> FragmentTransaction: add
    MainActivity ->> FragmentTransaction: commit
    FragmentTransaction ->> FragmentManager: enqueueAction
    
  • [:4:0] mManager.enqueueAction(this, allowStateLoss);

    // androidx.fragment.app.FragmentManager
        void enqueueAction(@NonNull OpGenerator action, boolean allowStateLoss) {
            ...
                mPendingActions.add(action);
       [:4:0:0] scheduleCommit();
            ...
        }
    
    // androidx.fragment.app.FragmentManager
        private final ArrayList<OpGenerator> mPendingActions = new ArrayList<>();
    
    // androidx.fragment.app.FragmentManager
        interface OpGenerator {
            /**
             * Generate transactions to add to {@code records} and whether or not the transaction is
             * an add or pop to {@code isRecordPop}.
             *
             * records and isRecordPop must be added equally so that each transaction in records
             * matches the boolean for whether or not it is a pop in isRecordPop.
             *
             * @param records A list to add transactions to.
             * @param isRecordPop A list to add whether or not the transactions added to records is
             *                    a pop transaction.
             * @return true if something was added or false otherwise.
             */
            boolean generateOps(@NonNull ArrayList<BackStackRecord> records,
                    @NonNull ArrayList<Boolean> isRecordPop);
        }
    
    sequenceDiagram
    autonumber
    
    participant MainActivity
    participant FragmentManager
    participant FragmentTransaction
    participant BackStackRecord
    
    MainActivity ->> FragmentManager: beginTransaction
    FragmentManager ->> FragmentTransaction: new
    FragmentManager ->> BackStackRecord: new
    FragmentManager ->> MainActivity: return (FragmentTransaction)BackStackRecord
    MainActivity ->> FragmentTransaction: add
    MainActivity ->> FragmentTransaction: commit
    FragmentTransaction ->> FragmentManager: enqueueAction
    FragmentManager ->> FragmentManager: mPendingActions.add
    
    classDiagram
    class FragmentTransaction {
        mOps: ArrayList"OP"
    }
    class BackStackRecord
    class FragmentManager {
        mPendingActions: ArrayList"OpGenerator"
    }
    class `FragmentManager-BackStackEntry`
    class `FragmentManager-OpGenerator`
    class `FragmentTransaction-Op` {
        mCmd: int
        mFragment: Fragment
    }
    
    BackStackRecord --|> FragmentTransaction: extends
    BackStackRecord --|> `FragmentManager-BackStackEntry`: impl
    BackStackRecord --|> `FragmentManager-OpGenerator`: impl
    FragmentManager --> BackStackRecord: create
    FragmentTransaction --> `FragmentTransaction-Op`: holds
    FragmentManager --> `FragmentManager-OpGenerator`: holds
    
  • [:4:0:0] scheduleCommit();

    // androidx.fragment.app.FragmentManager
        void scheduleCommit() {
            synchronized (mPendingActions) {
                    ...
          [:4:0:0:0] mHost.getHandler().post(mExecCommit);
                    ...
        }
    
    sequenceDiagram
    autonumber
    
    participant MainActivity
    participant FragmentManager
    participant FragmentTransaction
    participant BackStackRecord
    
    MainActivity ->> FragmentManager: beginTransaction
    FragmentManager ->> FragmentTransaction: new
    FragmentManager ->> BackStackRecord: new
    FragmentManager ->> MainActivity: return (FragmentTransaction)BackStackRecord
    MainActivity ->> FragmentTransaction: add
    MainActivity ->> FragmentTransaction: commit
    FragmentTransaction ->> FragmentManager: enqueueAction
    FragmentManager ->> FragmentManager: mPendingActions.add
    FragmentManager ->> FragmentManager: scheduleCommit
    
  • [:4:0:0:0] mHost.getHandler().post(mExecCommit)
    mExecCommit ⬇️被放入消息队列,之后会被执行。

        // androidx.fragment.app.FragmentManager
        private Runnable mExecCommit = new Runnable() {
            @Override
            public void run() {
      [:4:0:0:0:0] execPendjingActions(true);
            }
        };
    
  • [:4:0:0:0:0] execPendjingActions(true);

        // androidx.fragment.app.FragmentManager
        boolean execPendingActions(boolean allowStateLoss) {
            ensureExecReady(allowStateLoss);
    
    [:4:0:0:0:0:0]while (generateOpsForPendingActions(mTmpRecords, mTmpIsPop)) {
                mExecutingActions = true;
                try {
     [:4:0:0:0:0:1] removeRedundantOperationsAndExecute(mTmpRecords, mTmpIsPop);
                    ...
    
    sequenceDiagram
    autonumber
    
    participant MainActivity
    participant FragmentManager
    participant FragmentTransaction
    participant BackStackRecord
    
    MainActivity ->> FragmentManager: beginTransaction
    FragmentManager ->> FragmentTransaction: new
    FragmentManager ->> BackStackRecord: new
    FragmentManager ->> MainActivity: return (FragmentTransaction)BackStackRecord
    MainActivity ->> FragmentTransaction: add
    MainActivity ->> FragmentTransaction: commit
    FragmentTransaction ->> FragmentManager: enqueueAction
    FragmentManager ->> FragmentManager: mPendingActions.add
    FragmentManager ->> FragmentManager: scheduleCommit
    FragmentManager ->> FragmentManager: execPendingActions
    
  • [:4:0:0:0:0:0] generateOpsForPendingActions(mTmpRecords, mTmpIsPop)

        // androidx.fragment.app.FragmentManager
        private boolean generateOpsForPendingActions(@NonNull ArrayList<BackStackRecord> records,
                @NonNull ArrayList<Boolean> isPop) {
                ...
                for (int i = 0; i < numActions; i++) {
      [:4:0:0:0:0:0:0] didSomething |= mPendingActions.get(i).generateOps(records, isPop);
                }
                ...
        }
    

    这里对mPendingActions中的每一个Action都调用generateOps——会处理到之前在[:4:0]添加的Action

    sequenceDiagram
    autonumber
    
    participant MainActivity
    participant FragmentManager
    participant FragmentTransaction
    participant BackStackRecord
    participant OpGenerator
    
    MainActivity ->> FragmentManager: beginTransaction
    FragmentManager ->> FragmentTransaction: new
    FragmentManager ->> BackStackRecord: new
    FragmentManager ->> MainActivity: return (FragmentTransaction)BackStackRecord
    MainActivity ->> FragmentTransaction: add
    MainActivity ->> FragmentTransaction: commit
    FragmentTransaction ->> FragmentManager: enqueueAction
    FragmentManager ->> FragmentManager: mPendingActions.add
    FragmentManager ->> FragmentManager: scheduleCommit
    FragmentManager ->> FragmentManager: execPendingActions
    FragmentManager ->> OpGenerator: generateOps
    OpGenerator ->> BackStackRecord: generateOps
    
    classDiagram
    class FragmentTransaction {
        mOps: ArrayList"OP"
    }
    class BackStackRecord
    class FragmentManager {
        mPendingActions: ArrayList"OpGenerator"
    }
    class `FragmentManager-BackStackEntry`
    class `FragmentManager-OpGenerator` {
        boolean generateOps()
    }
    class `FragmentTransaction-Op` {
        mCmd: int
        mFragment: Fragment
    }
    
    BackStackRecord --|> FragmentTransaction: extends
    BackStackRecord --|> `FragmentManager-BackStackEntry`: impl
    BackStackRecord --|> `FragmentManager-OpGenerator`: impl
    FragmentManager --> BackStackRecord: create
    FragmentTransaction --> `FragmentTransaction-Op`: holds
    FragmentManager --> `FragmentManager-OpGenerator`: holds
    
  • [:4:0:0:0:0:0:0] mPendingActions.get(i).generateOps(records, isPop)

        // androidx.fragment.app.BackStackRecord
        public boolean generateOps(@NonNull ArrayList<BackStackRecord> records,
                @NonNull ArrayList<Boolean> isRecordPop) {
    
            ...
            records.add(this);
            ...
        }
    

    BackStackRecord将自己添加到传入的records

  • [:4:0:0:0:0:1] removeRedundantOperationsAndExecute(mTmpRecords, mTmpIsPop)
    遍历[:4:0:0:0:0:0]返回的每一个record,对其处理

        // androidx.fragment.app.FragmentManager
        private void removeRedundantOperationsAndExecute(@NonNull ArrayList<BackStackRecord> records,
                @NonNull ArrayList<Boolean> isRecordPop) {
            ...
            final int numRecords = records.size();
    
            for (int recordNum = 0; recordNum < numRecords; recordNum++) {
                ...
                       int reorderingEnd = recordNum + 1;
      [:4:0:0:0:0:1:0] executeOpsTogether(records, isRecordPop, recordNum, reorderingEnd);
                ...
            }
        }
    

    遍历执行record,executeOpsTogether(records传入了整个records——只有一个OP_ADD,通过后面两个参数指定要执行的 record的开始位置和结束位置——recordNum(0)和reorderingEnd(recordNum + 1 = 0 + 1 = 1),也就相当于挨个执行。

    sequenceDiagram
    autonumber
    
    participant MainActivity
    participant FragmentManager
    participant FragmentTransaction
    participant BackStackRecord
    participant OpGenerator
    
    MainActivity ->> FragmentManager: beginTransaction
    FragmentManager ->> FragmentTransaction: new
    FragmentManager ->> BackStackRecord: new
    FragmentManager ->> MainActivity: return (FragmentTransaction)BackStackRecord
    MainActivity ->> FragmentTransaction: add
    MainActivity ->> FragmentTransaction: commit
    FragmentTransaction ->> FragmentManager: enqueueAction
    FragmentManager ->> FragmentManager: mPendingActions.add
    FragmentManager ->> FragmentManager: scheduleCommit
    FragmentManager ->> FragmentManager: execPendingActions
    FragmentManager ->> OpGenerator: generateOps
    OpGenerator ->> BackStackRecord: generateOps
    FragmentManager ->> FragmentManager: removeRedundantOperationsAndExecute
    
  • [:4:0:0:0:0:1:0] executeOpsTogether(records, isRecordPop, recordNum, reorderingEnd)

        // androidx.fragment.app.FragmentManager
        private void executeOpsTogether(@NonNull ArrayList<BackStackRecord> records,
                @NonNull ArrayList<Boolean> isRecordPop, int startIndex, int endIndex) {
            ...
    [:4:0:0:0:0:1:0:0] executeOps(records, isRecordPop, startIndex, endIndex);
            ...
             [:4:0:0:0:0:1:0:1] fragmentStateManager.moveToExpectedState();
            ...
            
            ...
    

    startIndex: recordNum = 0
    endIndex: reorderingEnd = 1

  • [:4:0:0:0:0:1:0:0] executeOps(records, isRecordPop, startIndex, endIndex);

        // androidx.fragment.app.FragmentManager
        private static void executeOps(@NonNull ArrayList<BackStackRecord> records,
            @NonNull ArrayList<Boolean> isRecordPop, int startIndex, int endIndex) {
            for (int i = startIndex; i < endIndex; i++) {
     [:4:0:0:0:0:1:0:0:0] record.executeOps();
                }
            }
        }
    
    sequenceDiagram
    autonumber
    
    participant MainActivity
    participant FragmentManager
    participant FragmentTransaction
    participant BackStackRecord
    participant OpGenerator
    
    MainActivity ->> FragmentManager: beginTransaction
    FragmentManager ->> FragmentTransaction: new
    FragmentManager ->> BackStackRecord: new
    FragmentManager ->> MainActivity: return (FragmentTransaction)BackStackRecord
    MainActivity ->> FragmentTransaction: add
    MainActivity ->> FragmentTransaction: commit
    FragmentTransaction ->> FragmentManager: enqueueAction
    FragmentManager ->> FragmentManager: mPendingActions.add
    FragmentManager ->> FragmentManager: scheduleCommit
    FragmentManager ->> FragmentManager: execPendingActions
    FragmentManager ->> OpGenerator: generateOps
    OpGenerator ->> BackStackRecord: generateOps
    FragmentManager ->> FragmentManager: removeRedundantOperationsAndExecute
    FragmentManager ->> FragmentManager: executeOpsTogether
    FragmentManager ->> FragmentManager: executeOps
    FragmentManager ->> BackStackRecord: executeOps
    
    classDiagram
    class FragmentTransaction {
        mOps: ArrayList"OP"
    }
    class BackStackRecord {
        executeOps(): void
    }
    class FragmentManager {
        mPendingActions: ArrayList"OpGenerator"
    }
    class `FragmentManager-BackStackEntry`
    class `FragmentManager-OpGenerator` {
        boolean generateOps()
    }
    class `FragmentTransaction-Op` {
        mCmd: int
        mFragment: Fragment
    }
    
    BackStackRecord --|> FragmentTransaction: extends
    BackStackRecord --|> `FragmentManager-BackStackEntry`: impl
    BackStackRecord --|> `FragmentManager-OpGenerator`: impl
    FragmentManager --> BackStackRecord: create
    FragmentTransaction --> `FragmentTransaction-Op`: holds
    FragmentManager --> `FragmentManager-OpGenerator`: holds
    
  • [:4:0:0:0:0:1:0:0:0] record.executeOps();

        // androidx.fragment.app.BackStackRecord
        void executeOps() {
            final int numOps = mOps.size();
            for (int opNum = 0; opNum < numOps; opNum++) {
                switch (op.mCmd) {
                    case OP_ADD:
                        f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim);
                        mManager.setExitAnimationOrder(f, false);
    [:4:0:0:0:0:1:0:0:0:0] mManager.addFragment(f);
                        break;
    

    mOps的数量为1——[:3:0:1] 添加的OP_ADD

    sequenceDiagram
    autonumber
    
    participant MainActivity
    participant FragmentManager
    participant FragmentTransaction
    participant BackStackRecord
    participant OpGenerator
    
    MainActivity ->> FragmentManager: beginTransaction
    FragmentManager ->> FragmentTransaction: new
    FragmentManager ->> BackStackRecord: new
    FragmentManager ->> MainActivity: return (FragmentTransaction)BackStackRecord
    MainActivity ->> FragmentTransaction: add
    MainActivity ->> FragmentTransaction: commit
    FragmentTransaction ->> FragmentManager: enqueueAction
    FragmentManager ->> FragmentManager: mPendingActions.add
    FragmentManager ->> FragmentManager: scheduleCommit
    FragmentManager ->> FragmentManager: execPendingActions
    FragmentManager ->> OpGenerator: generateOps
    OpGenerator ->> BackStackRecord: generateOps
    FragmentManager ->> FragmentManager: removeRedundantOperationsAndExecute
    FragmentManager ->> FragmentManager: executeOpsTogether
    FragmentManager ->> FragmentManager: executeOps
    FragmentManager ->> BackStackRecord: executeOps
    BackStackRecord ->> FragmentManager: addFragment
    
  • [:4:0:0:0:0:1:0:0:0:0] mManager.addFragment(f);

        // androidx.fragment.app.FragmentManager
        FragmentStateManager addFragment(@NonNull Fragment fragment) {
            if (isLoggingEnabled(Log.VERBOSE)) Log.v(TAG, "add: " + fragment);
            FragmentStateManager fragmentStateManager = createOrGetFragmentStateManager(fragment);
            fragment.mFragmentManager = this;
            mFragmentStore.makeActive(fragmentStateManager);
            if (!fragment.mDetached) {
                mFragmentStore.addFragment(fragment);
                fragment.mRemoving = false;
                if (fragment.mView == null) {
                    fragment.mHiddenChanged = false;
                }
                if (isMenuAvailable(fragment)) {
                    mNeedMenuInvalidate = true;
                }
            }
            return fragmentStateManager;
        }
    
  • [:4:0:0:0:0:1:0:1] fragmentStateManager.moveToExpectedState()
    这里回到上面说过的 [:1:0:0:1]

参考