Fragment life cycle

How to understand that the Fragment starts from onAttach during the onCreate execution of the Activity? How does this process work?

The trigger method for this process is actually the setContentView in the Activity’s onCreate method, or more accurately, the LayoutInflater.inflate triggered by the setContentView to resolve the layout, The Activity itself is the implementation class of LayoutInflater.Factory. The onCreateView method is responsible for parsing fragment elements in the XML layout and triggering the fragment reflection instantiation. After that, the onCreate method of FragmentActivity calls moveToState on the instantiated Fragment to migrate the Fragment state, triggering the Fragment life cycle.

Fragmenet and View have similarities and differences

Fragment is more like a complex ViewGroup, complex in two ways:

  • It has its own life cycle;
  • There is a return stack.

But fragments also have their own unique places, that is, they move where they are and when they are used; Fragment is used with hide, show, remove, add, replace, and other transactions, so that an Activity can jump to different pages, but it is really just a switch within a region of the page. This is where fragments differ from viewgroups — frequent switching of Fragment objects leads to frequent content switching, since viewgroups are usually fixed and not frequently switched.

This leads to the need to reuse fragments, and hence the need for Fragment transactions and stack rollback.

Fragment and Activity are different and similar

Fragments feel like activities because they have a similar lifecycle, but that’s the difference:

  • The Activity life cycle is controlled by the system;

  • The Fragment’s life cycle is accompanied by a callback to the Activity’s life cycle method onXXX. The FragmentActivity executes the mFragmentManager’s dispatchXXX method inside to cause the Fragment’s state to shift. Life cycle calls to fragments occur; The Fragment life cycle is an application layer that is controlled by an Activity. The idea of a Fragment transaction is to actively change the state of the Fragment and make that state exist temporarily outside the host Activity.

Activity and FragmentManager

It’s not easy to get FragmentManager in your Activity.

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

public FragmentManager getFragmentManager(a) {
    return mFragments.getFragmentManager();
}
Copy the code

As you can see, obtaining the FragmentManager in the Activity is not straightforward. Instead, the FragmentController object is handed over to the Activity. The FragmentController object is initialized in place.

// FragmentController.java
private finalFragmentHostCallback<? > mHost;public static final FragmentController createController(FragmentHostCallback
        callbacks) {
    // The constructor is called to initialize, but the constructor is private and can only be used statically
    return new FragmentController(callbacks);
}

private FragmentController(FragmentHostCallback
        callbacks) {
    mHost = callbacks;
}

public FragmentManager getFragmentManager(a) {
    // It passes the job of getting the FragmentManager to the mHost attribute, which is passed in the constructor
    return mHost.getFragmentManagerImpl();
}
Copy the code

As you can see, the final call to get the FragmentManager is made by mHost, and the actual method implementation is the parent class of the initial HostCallbacks — FragmentHostCallback:

//FragmentHostCallback.java
public abstract class FragmentHostCallback<E> extends FragmentContainer {
    
    final FragmentManagerImpl mFragmentManager = new FragmentManagerImpl();
    FragmentManagerImpl getFragmentManagerImpl(a) {
        returnmFragmentManager; }}Copy the code

Clearly, it is the initialized FragmentManagerImpl object.

Remark: Actually browse = = FragmentController = = method implementation of this class can be found that the realization of all the methods in this class are mHost. MFragmentManager. XXX, therefore, We can treat the FragmentController as if it were a FragmentManagerImpl!!

Core class

Core attributes display:

// FragmentManager.java(androidx)
public abstract class FragmentManager {
	private final ArrayList<OpGenerator> mPendingActions = new ArrayList<>();  // indicates whether the operation is on or off the stack
	ArrayList<BackStackRecord> mBackStack;  // The element is the BackStackRecord object for each transaction commit
	private final FragmentStore mFragmentStore = new FragmentStore();   // As the name implies, the FragmentManager manages fragments that have already been addedFragmentHostCallback<? > mHost; FragmentContainer mContainer;// FragmentHostCallback is the implementation class of FragmentContainer
    
    // There are three temporary lists, which will be used by the code during execution, but will be cleared after execution
    // Temporary vars for removing redundant operations in BackStackRecords:
    private ArrayList<BackStackRecord> mTmpRecords;
    private ArrayList<Boolean> mTmpIsPop;
    private ArrayList<Fragment> mTmpAddedFragments;
    
    int mCurState = Fragment.INITIALIZING;  // FragmentManager current state!!
}

// FragmentStore.java
class FragmentStore {
    private final ArrayList<Fragment> mAdded = new ArrayList<>();  // Fragment that has been added
    private final HashMap<String, FragmentStateManager> mActive = new HashMap<>();
}
Copy the code

Static Fragment loading

Static fragments are fragments defined by using the Fragment tag in the XML layout. The loading process is defined in the onCreateView method of the Activity. The Activity is the implementation class of the LayoutInflater. Delegate the implementation of this method to the mFragments property. From the analysis above, we know that in the FragmentActivity subclass, mFragments implement the FragmentController class. Therefore, Parsing Fragment tags in XML is left to the FragmentController:

//FragmentController.java

public View onCreateView(@Nullable View parent, @NonNull String name, @NonNull Context context,
            @NonNull AttributeSet attrs) {
    return mHost.mFragmentManager.getLayoutInflaterFactory()
                .onCreateView(parent, name, context, attrs);
}
Copy the code

Similarly, the mFragmentManager implementation class is the FragmentManagerImpl from the AndroidX package, so the loading process comes into FragmentManager:

// FragmentManager.java
private final FragmentLayoutInflaterFactory mLayoutInflaterFactory =
            new FragmentLayoutInflaterFactory(this);

// FragmentLayoutInflaterFactory.java
public View onCreateView(@Nullable View parent, @NonNull String name, @NonNull Context context,
            @NonNull AttributeSet attrs) {
        // Just parse the Fragment
        if (!"fragment".equals(name)) {
            return null;
        }
    
    	// Get the fully qualified class name of the Fragment
        String fname = attrs.getAttributeValue(null."class");
        TypedArray a =  context.obtainStyledAttributes(attrs, R.styleable.Fragment);
        if (fname == null) {
            // Get the fully qualified class name of the Fragment
            fname = a.getString(R.styleable.Fragment_android_name);
        }
    	// id
        int id = a.getResourceId(R.styleable.Fragment_android_id, View.NO_ID);
    	// tag
        String tag = a.getString(R.styleable.Fragment_android_tag);
        a.recycle();
        intcontainerId = parent ! =null ? parent.getId() : 0;
        
    	// Try reusing fragments first
    	// First pass findFragmentById of mFragmentManager
    	// Next, findFragmentByTag of mFragmentManager
    	// Finally try find using containerId via mFragmentManagerFragment fragment = id ! = View.NO_ID ? mFragmentManager.findFragmentById(id) :null;
        if (fragment == null&& tag ! =null) {
            fragment = mFragmentManager.findFragmentByTag(tag);
        }
        if (fragment == null&& containerId ! = View.NO_ID) { fragment = mFragmentManager.findFragmentById(containerId); }// If not reusable, instantiate the Fragment
        if (fragment == null) {
            fragment = mFragmentManager.getFragmentFactory().instantiate(
                    context.getClassLoader(), fname);
            // This tag indicates that the Fragment object is a Fragment loaded from an XML file
            fragment.mFromLayout = true; fragment.mFragmentId = id ! =0 ? id : containerId;
            fragment.mContainerId = containerId;
            fragment.mTag = tag;
            // Indicates that the Layout is added to the Layout
            fragment.mInLayout = true;
            fragment.mFragmentManager = mFragmentManager;
            fragment.mHost = mFragmentManager.mHost;
            fragment.onInflate(mFragmentManager.mHost.getContext(), attrs,
                    fragment.mSavedFragmentState);
            // This is actually added to the mFragmentStore of mFragmentManager
            mFragmentManager.addFragment(fragment);
            
            // Core!! State transition!!
            mFragmentManager.moveToState(fragment);

        } 

        // Execute moveToState again to migrate the state to CREATED
        if (mFragmentManager.mCurState < Fragment.CREATED && fragment.mFromLayout) {
            mFragmentManager.moveToState(fragment, Fragment.CREATED);
        } else {
            mFragmentManager.moveToState(fragment);
        }
        
        if(id ! =0) {
            fragment.mView.setId(id);
        }
        if (fragment.mView.getTag() == null) {
            fragment.mView.setTag(tag);
        }
        return fragment.mView;
    }
Copy the code

Here we can summarize the process of parsing fragment tags in XML layouts:

  1. The reuse stage: FragmentManager Attempts to reuse existing Fragment objects from the FragmentStore. The FragmentManager attempts to reuse existing Fragment objects from the FragmentStore with the following priorities
    1. Lookup by id attribute in layout;
    2. Lookup by tag attribute in layout;
    3. Find it using containerId.
  2. New Stage: If the Fragment is being parsed for the first time, the FragmentManager will use the FragmentFactory to initialize the Fragment by calling the no-argument constructor with reflection. Why you must provide a no-argument constructor when defining a Fragment; After creating the Fragment object, call mFragmentStrore’s add method to save the Fragment.
  3. State migration phase: When INITIALIZING the Fragment, perform moveToState first and migrate the Fragment to the FragmentManager default FragmentManager initial fragment.initializing state. Then, execute moveToState again to migrate the Fragment to the CREATED state.

It is also worth noting that LayoutInflaters parse XML files and return views, and that fragments are not subclasses of Views. So FragmentLayoutInflaterFactory work in LayoutInflater’s system, it is necessary to meet the requirements, so it can be seen that the aforementioned onCreateView returns the mView attribute of the fragments, So it’s this mView that ends up being added to the ViewGroup. A Fragment is not a View. Because of the Activity’s LayoutInflater.Factory2, the Fragment tag is blocked by the Activity in the layout file. LayoutInflater.Factory2 works in the architecture of LayoutInflaters parsing files and must satisfy layoutInflaters’ requirements. So its function implementation class FragmentLayoutInflaterFactory in onCreateView, eventually return fragments mView attributes, using this mechanism, to complete the behaviors of the fragments, The Fragment can be defined in a layout file like a View, but the Fragment itself is not a part of the View system. At the same time, the Fragment also acts as the owner and manager of the mView, giving the mView a relatively independent life cycle so that the mView can detach and attach to the Activity temporarily. This is something no ordinary ViewGroup or View can do. = =

Fragment reuse — FragmentStore

The above procedure involves reusing fragments. In FragmentManager, this process is broken down and handed over to the FragmentStore:

// FragmentManager.java
public Fragment findFragmentById(@IdRes int id) {
    return mFragmentStore.findFragmentById(id);
}

public Fragment findFragmentByTag(@Nullable String tag) {
    return mFragmentStore.findFragmentByTag(tag);
}

Fragment findFragmentByWho(@NonNull String who) {
    return mFragmentStore.findFragmentByWho(who);
}
Copy the code

As you can see, this is all assigned to the FragmentStore:

// FragmentStore.java
private final ArrayList<Fragment> mAdded = new ArrayList<>();  // The Fragment has been added
private final HashMap<String, FragmentStateManager> mActive = new HashMap<>();  // The current meaning is unknown

    Fragment findFragmentById(@IdRes int id) {
        // First look through added fragments.
        for (int i = mAdded.size() - 1; i >= 0; i--) {
            Fragment f = mAdded.get(i);
            if(f ! =null && f.mFragmentId == id) {
                returnf; }}// Now for any known fragment.
        for (FragmentStateManager fragmentStateManager : mActive.values()) {
            if(fragmentStateManager ! =null) {
                Fragment f = fragmentStateManager.getFragment();
                if (f.mFragmentId == id) {
                    returnf; }}}return null;
    }
Copy the code

Here, Byid is used as an example, and the discovery is traversal comparison, there is no special method. Remember that after parsing the Fragment object in the XML, you added it to the FragmentStore, which is the mAdded attribute above.

Fragment initialization — FragmentFactory

There is a mFragmentFactory in the FragmentManager that defaults to null. Users can specify a FragmentFactory object by calling the setFragmentFactory of the FragmentManager, There is also a mHostFragmentFactory, and the FragmentManager getFragmentFactory() method is implemented as follows:

// FragmentManager.java
private FragmentFactory mFragmentFactory = null;
private FragmentFactory mHostFragmentFactory = new FragmentFactory() {
    public Fragment instantiate(@NonNull ClassLoader classLoader, @NonNull String className) {
        return mHost.instantiate(mHost.getContext(), className, null); }};public FragmentFactory getFragmentFactory(a) {
    if(mFragmentFactory ! =null) {
        return mFragmentFactory;
    }
    if(mParent ! =null) {
            
        return mParent.mFragmentManager.getFragmentFactory();
    }
    return mHostFragmentFactory;
}
Copy the code

If setFragmentFactory is not called, mHostFragmentFactory is still returned. Its internal Fragment initialization uses FragmentHostCallback (mHost’s instantiate method) in its parent FragmentContainer:

// FragmentContainer.java
public Fragment instantiate(@NonNull Context context, @NonNull String className,
            @Nullable Bundle arguments) {
    // Use static methods of Fragment to initialize
    return Fragment.instantiate(context, className, arguments);
}

// Fragment.java
public static Fragment instantiate(@NonNull Context context, @NonNull String fname,
            @Nullable Bundle args) {
        try {
            Class<? extends Fragment> clazz = FragmentFactory.loadFragmentClass(
                    context.getClassLoader(), fname);
            // Classical calls have no arguments constructor
            Fragment f = clazz.getConstructor().newInstance();
            if(args ! =null) {
                args.setClassLoader(f.getClass().getClassLoader());
                f.setArguments(args);
            }
            returnf; }}Copy the code

Again, classic reflection usage, which is why you have to provide a no-parameter constructor for custom fragments!!

Fragment State transfer — moveToState

The mMaxState property of the Fragment is INITIALIZING by default. At the same time, the Fragment also has an mMaxState property which indicates the highest state that the Fragment can reach. Note that this mMaxState is Lifecycle. It’s just that there are values for each of these states in the Fragment, so we can think of it as a Fragment State. Lifecycle.State.

There are two mechanisms for Fragment management and state migration in FragmentManager, that is, there are two types of callback: moveToState(Fragment), moveToState(Fragment, int); The latter mechanism migrates the target Fragment to a specified state, while the former internal callback calls the latter, except that the second parameter sets the Fragment’s current state, mCurState.

In addition, FragmentManager has its own state, mCurState, shown above; Also, the FragmentManager provides a moveToState(int, Boolean) method to support its own state transitions. Also, the only way to change the mCurState of FragmentManager is with moveToState(int, Boolean).

4. The impact of the Activity life cycle on the Fragment life cycle when using the Fragment statically

We all know that activities manage fragments through the FragmentManager, and that the Fragment lifecycle is governed by the Activity lifecycle. Let’s explore how Activity lifecycle callbacks affect the Fragment lifecycle.

Attention!!!!! Fragment: Android x Fragment: Android X Fragment: Android X Fragment: Android X Fragment: Android X Fragment: Android X Fragment: Android X Fragment: Android X Fragment: Android X Fragment: Android X Fragment

Activity — onCreate

Let’s start by looking at the implementation of this method in FragmentActivity:

// FragmentActivity.java
protected void onCreate(@Nullable Bundle savedInstanceState) {...super.onCreate(savedInstanceState);

        
        mFragments.dispatchCreate();
    }
Copy the code

The mFragments property is an instance of a FragmentController, but its methods are delegated to the FragmentManager. Therefore, This is actually calling the FragmentManager dispatchCreate() method:

// FragmentManager.java
void dispatchCreate(a) {
    mStateSaved = false;
    mStopped = false;
    dispatchStateChange(Fragment.CREATED);
}

private void dispatchStateChange(int nextState) {
    try {
        mExecutingActions = true;
        mFragmentStore.dispatchStateChange(nextState);
        // Perform state migration. Note that since it is passed from the Activity, this represents migrating the state of the FragmentManager
        // So we call moveToState(int, Boolean)
        moveToState(nextState, false);
    } finally {
        mExecutingActions = false;
    }
    // When it comes to FragmentManager transactions, ignore them
    execPendingActions(true);
}
Copy the code

The implementation of this method, as well as the call process, is clearly shown above; In the meantime, we’re just going to focus on calling moveToState right now. Note that since this is passed from the Activity, it represents the state of migrating FragmentManager; So, I’m calling moveToState(int, Boolean); Also, the second argument is passed false.

// FragmentManager.java
void moveToState(int newState, boolean always) {... mCurState = newState; . }Copy the code

The above source code is the code that actually works in this execution. What makes it so special is the core point: == Now the Activity belongs to the onCreate method and the setContentView has not been executed. This means that the Fragment in the Layout file has not triggered parsing. At this point, no Fragment has been added to the FragmentManager’s mFragmentStore. At this point, this has only one role: synchronize the FragmentManager mCurState with the Activity, creating ==.

So what are the implications? Back to in the process of the Activity, the setContentView trigger FragmentLayoutInflaterFactory parsing fragments in the layout file labels, implementation has the following parts:

// FragmentLayoutInflaterFactory.java
// If not reusable, instantiate the Fragment
        if (fragment == null) {
            fragment = mFragmentManager.getFragmentFactory().instantiate(
                    context.getClassLoader(), fname);
            // This tag indicates that the Fragment object is a Fragment loaded from an XML file
            fragment.mFromLayout = true;
            
            // Indicates that the Layout is added to the Layout
            fragment.mInLayout = true;
            
            // This is actually added to the mFragmentStore of mFragmentManager
            mFragmentManager.addFragment(fragment);
            
            // Core!! State transition!!
            mFragmentManager.moveToState(fragment);
        } 
Copy the code

This part, the = = the most important thing is to two steps: mFragmentManager. AddFragment (fragments) and mFragmentManager. MoveToState (fragments). The former adds the Fragment object to the mFragmentStore so that the FragmentManager gets the fragment it needs to manage. Most importantly, the latter, performs state migration on newly created fragments! Also, since state migration is performed on the Fragment, the signature moveToState(Fragment) method is called. = =

// FragmentManager.java
void moveToState(@NonNull Fragment f) {
	// Notice that the FragmentManager's mCurState is CREATED!!
    moveToState(f, mCurState);
}

	void moveToState(@NonNull Fragment f, int newState) {
    	// Since this is the first time moveToState is executed on the Fragment, fragmentStateManager is null
        // Create a new if statement
        FragmentStateManager fragmentStateManager = mFragmentStore.getFragmentStateManager(f.mWho);
        if (fragmentStateManager == null) {
            fragmentStateManager = new FragmentStateManager(mLifecycleCallbacksDispatcher, f);
            // Here we initialize CREATED for internal properties
            fragmentStateManager.setFragmentManagerState(Fragment.CREATED);
        }
        
        // CREATED in the current case
        newState = Math.min(newState, fragmentStateManager.computeMaxState());
        if (f.mState <= newState) {
            switch (f.mState) {
                // Execute moveToState for the first time after parsing the fragment from XML
                // The Fragment's mState is INITIALIZING
                case Fragment.INITIALIZING:
                    if (newState > Fragment.INITIALIZING) {
                        ...
                        // After the execution, the Fragment state becomes ATTACHED, so the Fragment is matched to the next case
                        fragmentStateManager.attach(mHost, this, mParent);
                    }
                   
                case Fragment.ATTACHED:
                    if (newState > Fragment.ATTACHED) {
                        // After execution, the Fragment state changes to CREATED, so it matches the next case
                        fragmentStateManager.create();
                    }
                    
                case Fragment.CREATED:
                    // newState is CREATED, which satisfies the condition, and the if statement is entered
                    if (newState > Fragment.INITIALIZING) {
                        // Execute the Fragment onCreateView and onViewCreated lifecycle callbacks
                        // Because the two lifecycle callbacks do not define corresponding states
                        // So the Fragment mState is still CREATED
                        fragmentStateManager.ensureInflatedView();
                    }
                    
                    // Since the current Activity state is CREATED -- so is FragmentManager
                    // The Activity's onCreate process executes moveToState and stops there
                    if (newState > Fragment.CREATED) {
                        fragmentStateManager.createView(mContainer);
                        fragmentStateManager.activityCreated();
                        fragmentStateManager.restoreViewState();
                    }
               caseFragment.activity_created:}}... }Copy the code

From the code comments above, you can see how the Activity’s lifecycle callback affects the Fragment lifecycle callback:

  • The FragmentManager lifecycle state is synchronized with the Activity: The Activity lifecycle state is distributed by calling the dispatchCreate method of mFragments in onCreate. The FragmentManager receives the signal and synchronizes its state, mCurState, with the Activity. It’s easy to understand that FragmentManager itself is the tool class that an Activity uses to manage its fragments, and its state is naturally attached to Parent.
  • The Fragment lifecycle is limited by the Activity(FragmentManager) lifecycle: When the fragmentStateManager executes different methods to implement the Fragment life cycle method callback to implement the Fragment state transition, the fragmentStateManager executes different methods to implement the Fragment life cycle method callback. The current State of the Fragment is smaller than the State of the Activity(FragmentManager). The State of the Fragment is smaller than or equal to the current State of the Activity. A Fragment can transfer state only if its state cannot precede that of an Activity(FragmentManager).

At this point, we have seen the state transition of the onCreate phase of the Activity. We know from the code above that in the onCreate phase of the Activity, The Fragment executes onAttach, onCreate, onCreateView, and onViewCreated lifecycle callbacks in sequence.

According to the above explanation, we can get the following call flow diagram:

Activity.onCreate -- begin
    
	Fragment.onAttach
	Fragment.onCreate
	Fragment.onCreateView
	Fragment.onViewCreated
    
Activity.onCreate -- end
Copy the code

State at this time:

  • The Activity (FragmentManager) : CREATED;
  • Fragments: CREATED.

So how do subsequent life cycle calls continue?

Activity — onStart

Similarly, let’s look at the code implementation of onStart:

// FragmentActivity.java
@Override
    protected void onStart(a) {
        super.onStart();

        // Take a good look
        if(! mCreated) { mCreated =true; mFragments.dispatchActivityCreated(); }..// Familiar method call, except this time the distribution is start
        mFragments.dispatchStart();
    }
Copy the code

Without further explanation, we know that the result of this execution is a call to the FragmentManager moveToState(int, Boolean):

// FragmentManager.java
	void dispatchStart(a) {
        mStateSaved = false;
        mStopped = false;
        dispatchStateChange(Fragment.STARTED);
    }
    
    private void dispatchStateChange(int nextState) {
        try {
            mExecutingActions = true;
            mFragmentStore.dispatchStateChange(nextState);
            moveToState(nextState, false); }... }Copy the code

Familiar recipes, familiar flavors. But even though it calls the same way, it works much worse because at onCreate, the Fragment hasn’t been resolved or added to the mFragmentStore. So the moveToState method just changes the mCurState variable of the FragmentManager; The Fragment (int, Boolean) method executes the following flow:

// FragmentManager.java
void moveToState(int newState, boolean always) {
        // Synchronize the current lifecycle with the Activity
        mCurState = newState;

        // Since the Fragment has been added, the internal if method is performed on it for state migration
        for(Fragment f : mFragmentStore.getFragments()) { moveFragmentToExpectedState(f); }... }Copy the code

First, you must synchronize the current FragmentManager state with the Activity; Due to parse out the fragments of the object has been added to the mFragmentStore, so can be carried to the fragments moveFragmentToExceptedState method, as the name implies, This method must eventually execute moveToState(Fragment, int) to transfer the Fragment state.

// FragmentManager.java
	void moveFragmentToExpectedState(@NonNull Fragment f) {
    	// Perform a status transition
        moveToState(f);

    }
Copy the code

What happens to the code when state transitions are performed?

// FragmentManager.java
void moveToState(@NonNull Fragment f, int newState) {
    	// No longer null is obtained
        FragmentStateManager fragmentStateManager = mFragmentStore.getFragmentStateManager(f.mWho);
        // Result is STARTED
        newState = Math.min(newState, fragmentStateManager.computeMaxState());
    
        if (f.mState <= newState) {
            
            switch (f.mState) {
                ...
                case Fragment.CREATED:
                   
                    // Last time moveToState stopped there
                    // Since newState is now STARTED, the condition is met, so Fragmet can continue migrating
                    if (newState > Fragment.CREATED) {
                        For static use of fragments, this method does nothing and can be ignored
                        fragmentStateManager.createView(mContainer);
                        // After execution, the Fragment state is migrated to ACTIVITY_CREATED, thus matching to the next case
                        fragmentStateManager.activityCreated();
                        fragmentStateManager.restoreViewState();
                    }
                    
                case Fragment.ACTIVITY_CREATED:
                    // newState is STARTED, the condition is met, and the if statement is executed
                    if (newState > Fragment.ACTIVITY_CREATED) {
                        // After the method completes, the Fragment state moves to STARTED, so it matches the next case
                        fragmentStateManager.start();
                    }
                    
                case Fragment.STARTED:
                    // Obviously, newState does not satisfy this condition and we will stop there
                    if(newState > Fragment.STARTED) { fragmentStateManager.resume(); }}}... }Copy the code

In fact, with the onCreate phase explained, the moveToState(Fragment, int) process is much easier this time around. Compared to the last time, the Activity’s life cycle has changed to a STARTED, so the Fragment’s life cycle can migrate to this upper STARTED. At the end of the onCeate phase, the Fragment state is CREATED(onCreateView and onViewCreated have no corresponding state defined). During the Fragment life cycle, There is also an ACTIVITY_CREATED between CRAETED and STARTED, so this moveToState(Fragment, int) is a migration of the Fragment to complete the two steps.

The Fragment executes onActivityCreated and onStart callbacks during the onStart phase of the Activity. The Fragment executes onActivityCreated and onStart callbacks during the onStart phase.

According to the above explanation, we can get the following call flow diagram:

Activity.onCreate -- begin
    
	Fragment.onAttach
	Fragment.onCreate
	Fragment.onCreateView
	Fragment.onViewCreated
    
Activity.onCreate -- end
Activity.onStart  -- begin
    
    Fragment.onActivityCreated
    Fragment.onStart
    
Activity.onStart  -- end
Copy the code

State at this time:

  • The Activity (FragmentManager) : STARTED;
  • Fragments: STARTED.

So how do subsequent life cycle calls continue?

Activity — onResume

Similarly, the onResume method passes through a slightly more complicated process, and the entry is the Activity’s performResume:

// Activity.java
final void performResume(boolean followedByPause, String reason) {
        
        onPostResume();  
    }

// FragmentActivity.java
	protected void onPostResume(a) {
        super.onPostResume();
        onResumeFragments();
    }
    
    protected void onResumeFragments(a) {
        mFragmentLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME);
        mFragments.dispatchResume();
    }
Copy the code

In fact, the next step is exactly the same as the onStart process, so here is the code for moveToState directly posted:

// FragmentManager.java
// FragmentManager.java
void moveToState(@NonNull Fragment f, int newState) {
    	// No longer null is obtained
        FragmentStateManager fragmentStateManager = mFragmentStore.getFragmentStateManager(f.mWho);
        // The RESUMED
        newState = Math.min(newState, fragmentStateManager.computeMaxState());
    
        if (f.mState <= newState) {
            switch (f.mState) {
                ...
                
                case Fragment.STARTED:
                    // In this case, newState satisfies this condition and does not stop at executing the if statement
                    if (newState > Fragment.STARTED) {
                        // After the method completes, the Fragment state migrates to RESUMEDfragmentStateManager.resume(); }}}... }Copy the code

The Fragment executes the onResume lifecycle callback during the onResume phase of the Activity.

According to the above explanation, we can get the following call flow diagram:

Activity.onCreate -- begin
    
	Fragment.onAttach
	Fragment.onCreate
	Fragment.onCreateView
	Fragment.onViewCreated
    
Activity.onCreate -- end
Activity.onStart  -- begin
    
    Fragment.onActivityCreated
    Fragment.onStart
    
Activity.onStart  -- end
Activity.onResume -- begin
    
    Fragment.onResume
    
Activity.onResume -- end
Copy the code

State at this time:

  • The Activity (FragmentManager) : RESUMED;
  • Fragments: RESUMED.

The Activity lifecycle controls the Fragment when using it statically.

summary

At this point in the analysis, let’s make a summary:

  • FragmentManager vs. Activity: The FragmentManager is a helper class for an Activity whose state is synchronized with the Activity’s lifecycle state. In its own lifecycle callback, the Activity issues instructions to the FragmentManager, which then migrates the state of the Fragment it manages. The Activity calls the FragmentManager dispatchXX method within its lifecycle method to distribute lifecycle items to each Fragment.
  • Fragment and View: When using a Fragment in a layout file, the Fragment returns an mView when it is parsed out. The Fragment behaves like a View because of the mView. Unlike views, Fragments have their own life cycle, which is tied to the Activity’s life cycle. == With this feature, actions that would otherwise be performed in the Activity’s lifecycle methods can be placed in the Fragment, reducing the Activity’s workload ==.