Reading Notes-Art Exploration-Life Cycle of Activity

1. Activity life cycle

1.0 Preface

This article summarizes the "Exploration of Android Development Art" by Mr. Ren Yugang. The [example] in the article is here

1.1 General introduction of Activity

In Android development, under normal circumstances, except for Window, Dialog, and Toast, the only interface we can see is Activity. So there is no doubt that Activity is very important.

In normal development, there may be few practical applications such as the life cycle of Activity, the matching rules of Flags, IntentFilter, and the matching process of Intent, so it is still relatively unfamiliar, but Activity needs to have a deep understanding of an application and optimize an application. It is still very important in terms of procedures and so on, so let's review it now:

1.2 Activity life cycle

1.2.1 Lifecycle in a typical case

The typical situation is the normal situation... The abnormal situation will be discussed in the next section. Let's start with a picture that all Android learners have seen:

  • (1) onCreate : 表示Activitybeing created, some initialization work is usually done in this method, such as calling setContentView to load layout resources, initializing the data required by the Activity, etc. [Example: For a specific Activity, the first startup callback is as follows: onCreate -> onStart -> onResume]

  • (2) onStart : Indicates Activitybeing activated, about to start, this is Activityalready visible, but not yet in the foreground (still in the background), and can't interact with the user yet. At this time, it can be understood that the Activity has been displayed, but we can't see it yet.

  • (3) onResume : Indicates Activityalready visible, andand appear in the foregroundAnd start the activity, and then the Activity is fully running.

  • (4) onPause : Indicates Activitystopping, under normal circumstances, onStop will be called immediately. In special cases, if you quickly return to the current Activity at this time, onResume will be called (in extreme cases, it is difficult for users to reproduce this situation). At this time, you can do some work such as storing the number and stopping the animation, but it should not be too time-consuming, because this will affect the display of the new Activity, onPause must be executed first, and the onResume of the new Activity will be executed.

  • (5) onStop : Indicates Activityabout to stop, you can do some slightly heavyweight recycling work, and it can't be too time-consuming. [Example: When the user opens a new Activity/switches to the desktop/turns off the screen: onPause -> onStop (special case: if the new Activity uses a transparent theme or a dialog, the current Activity will not call back onStop), and return to the original Activity, onRestart -> onStart -> onResume]

  • (6) onRestart : Indicates Activityrestarting, in general, when the current Activity starts fromInvisible becomes visible againstate, onRestart will be called.

  • (7) onDestory : Indicates Activityabout to be destroyed, which is the last callback of the Activity life cycle, where some recycling work and final resource release can be done. [Example: When the user presses the back button to go back, onPause -> onStop -> onDestory is called back]

1.2.2 A question: Assuming that the current Activity is A, if the user opens a new Activity B at this time, which of B's ​​onResume and A's onPause will be executed first?

  The source code of the Activity startup process is quite complicated. In short, the request to start the Activity will be handled by Instrumentation, and then send a request to the ActivityManagerService (AMS) through the Binder. AMS internally maintains an ActivityStack and is responsible for the status of the Activity in the stack. Synchronization, AMS synchronizes the state of Activity through ActivityThread to complete the invocation of life cycle methods. (can not read it)

  In the resumeTopActivityInnerLocked method in ActivityStack, there is such a piece of code:

//ActivityStack.resumeTopActivityInnerLocked()
// If the flag RESUME_WHILE_PAUSING is set, then continue to schedule the previous activity
// to be paused, while at the same time resuming the new resume activity only if the
// previous activity can't go into Pip since we want to give Pip activities a chance to
// enter Pip before resuming the next activity.
final boolean resumeWhilePausing = (next.info.flags & FLAG_RESUME_WHILE_PAUSING) != 0
        && !lastResumedCanPip;

boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, next, false);
if (mResumedActivity != null) {
    if (DEBUG_STATES) Slog.d(TAG_STATES,
            "resumeTopActivityLocked: Pausing " + mResumedActivity);
    pausing |= startPausingLocked(userLeaving, false, next, false);
}

  The above code means that before the new Activity starts, the Activity at the top of the stack needs to be onPause before the new Activity can be started. Finally, the following code is called in the realStartActivityLocked method in ActivityStackSupervisor:

//ActivityStackSupervisor.realStartActivityLocked()
app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
    System.identityHashCode(r), r.info,
    // TODO: Have this take the merged configuration instead of separate global and
    // override configs.
    mergedConfiguration.getGlobalConfiguration(),
    mergedConfiguration.getOverrideConfiguration(), r.compat,
    r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,
    r.persistentState, results, newIntents, !andResume,
    mService.isNextTransitionForward(), profilerInfo);

  The type of this app.thread is IApplicationThread, and the specific implementation of IApplicationThread is ApplicationThread in ActivityThread. So this code is actually transferred to ActivityThread, that is, the scheduleLaunchActivity method of ApplicationThread, and the scheduleLaunchActivity method will eventually complete the calling process of onCreate, onStart, and onResume of the new Activity. Therefore it can be concluded thatConclusion: The old Activiy first onPause, then the new Activity starts (onCreate, onStart, onResume), and the old activity calls onStop

  ActivityStackSupervisor.scheduleLaunchActivity will eventually call the following code to complete the calling process of onCreate, onStart, and onResume:

//ActivityThread.handleLaunchActivity()
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
        // If we are getting ready to gc after going to the background, well
        // we are back active so skip it.
        unscheduleGcIdler();
        mSomeActivitiesChanged = true;

        if (r.profilerInfo != null) {
            mProfiler.setProfiler(r.profilerInfo);
            mProfiler.startProfiling();
        }

        // Make sure we are running with the most recent config.
        handleConfigurationChanged(null, null);

        if (localLOGV) Slog.v(
            TAG, "Handling launch of " + r);

        // Initialize before creating the activity
        WindowManagerGlobal.initialize();

        Activity a = performLaunchActivity(r, customIntent);

        if (a != null) {
            r.createdConfig = new Configuration(mConfiguration);
            reportSizeConfigurations(r);
            Bundle oldState = r.state;
            handleResumeActivity(r.token, false, r.isForward,
                    !r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);

        ......
}

From another point of view, by analyzing this problem, we know that neither onPause nor onStop can perform time-consuming operations, especially onPause, which also means that we should try to do operations in onStop, so that the new Activity can be displayed as soon as possible Come out to the front desk.

[Example: When starting a new Activity, whether the onPause of the old Activity is executed first, and then the new Activity is started].

1.2.3 Life cycle analysis under abnormal conditions

1.2.3.1 Case 1: A change in resource-related resource configuration causes the Activity to be killed and recreated

Briefly explain the resource loading mechanism: using pictures, when we put a picture method in the drawable directory, we can get the pictures in this chapter through Resources. At the same time, in order to be compatible with different devices, we may also need to prevent different photos in some other directories, such as drawable-mdpi, drawable=hdpi, drawable-land, etc. In this way, when the application starts, the system will load the appropriate Resources resources according to the current device conditions. For example, the horizontal screen mobile phone and the vertical screen mobile phone will get two different pictures (the pictures in the landscape or portrait state are set ). For example, the current Activity is in the vertical screen state. If the screen is suddenly rotated, the Activity will be destroyed and recreated by default due to the system configuration change. Of course, we can also prevent the system from recreating the Activity.

By default, if the Activity does not do special processing, then when the system configuration changes, the Activity will be destroyed and recreated, and its life cycle is as follows:

When the system configuration is changed, the Activity will be destroyed, and its onPause, onStop, and onDestory will be called. At the same time, because the Activity is terminated in an abnormal situation, the system will call onSaveInstanceState to save the current Activity state. The call timing of this method is before onStop, and it has no established timing relationship with onPause. It should be noted that this method will only appear when the Activity is terminated abnormally. Under normal circumstances, the system will not call back this method.When the Activity is recreated, the system will call onRestoreInstanceState, and pass the Bundle object saved by the onSaveInstanceState method when the Activity is destroyed as a parameter to the onRestoreInstanceState and onCreate methods at the same time. Therefore, we can use the onRestoreInstanceState and onCreate methods to determine whether the Activity has been rebuilt. If so, we can take out the previously saved data and restore it (during the Activity rebuilding process, the system automatically does some rebuilding work for us. Each View has onSaveInstanceState and onRestoreInstanceState methods, you can see what data the system restores for each View by looking at the specific implementation).

Process to save and restore View hierarchy:Activity is terminated unexpectedly -> Activity calls onSaveInstanceState to save data -> Activity entrusts Window to save data -> Window entrusts top-level container (ViewGroup, usually DecorView) above it to save data -> top-level container then notifies its child elements to save data one by one data(Typical delegation thinking).

Let's take TextView as an example to analyze what data it saves:

//TextView.onSaveInstanceState()
@Override
    public Parcelable onSaveInstanceState() {
        Parcelable superState = super.onSaveInstanceState();

        // Save state if we are forced to
        final boolean freezesText = getFreezesText();
        boolean hasSelection = false;
        int start = -1;
        int end = -1;

        if (mText != null) {
            start = getSelectionStart();     //保存文本选中状态(Text selected state)
            end = getSelectionEnd();
            if (start >= 0 || end >= 0) {
                // Or save state if there is a selection
                hasSelection = true;
            }
        }

        if (freezesText || hasSelection) {
            SavedState ss = new SavedState(superState);

            if (freezesText) {
                if (mText instanceof Spanned) {
                    final Spannable sp = new SpannableStringBuilder(mText);

                    if (mEditor != null) {
                        removeMisspelledSpans(sp);
                        sp.removeSpan(mEditor.mSuggestionRangeSpan);
                    }

                    ss.text = sp;
                } else {
                    ss.text = mText.toString();     //保存文本内容(Text content)
                }
            }

            if (hasSelection) {
                // XXX Should also save the current scroll position!
                ss.selStart = start;
                ss.selEnd = end;
            }

            if (isFocused() && start >= 0 && end >= 0) {
                ss.frozenWithFocus = true;
            }

            ss.error = getError();

            if (mEditor != null) {
                ss.editorState = mEditor.saveInstanceState();
            }
            return ss;
        }

        return superState;
    }

Simple understanding: the system will only call when the Activity terminates abnormallyonSaveInstanceStateandonRestoreInstanceStateto store and restore data, other conditions do not trigger this process.
[Example: Data storage and restoration when the activity is re-created (screen rotation) under abnormal circumstances]

1.2.3.2 Case 2: Insufficient resource memory causes low-priority activities to be killed

Activity is divided into the following three types according to the priority from high to low:
(1) Foreground Activity —— The activity that is interacting with the user has the highest priority.
(2) Visible but non-foreground Activity —— For example, a dialog box pops up in the Activity, which causes the Activity to be visible but in the background and unable to directly interact with the user.
(3) Background Activity —— Activity that has been suspended, such as executing onStop, has the lowest priority.

When the system memory is insufficient, the system will kill the process of the target Activity according to the above priority, and then store and restore data through onSaveInstanceState and onRestoreInstanceState (the process is exactly the same as that of Case 1). If there are no four components executing in a process, the process is quickly killed by the system. Therefore, some background work is not suitable for running in the background independently of the four components. A better way is to put the background work into the Service to ensure that the process has a certain priority, so that it will not be easily killed by the system.

What I said above is that when the system configuration changes, the Activity will be re-created. The following is the method of not re-creating: specify the configChanges attribute to the Activity, for example, do not want the Activity to be re-created when the screen is rotated:

    android:configChanges = "orientation"
item (commonly used) meaning
locale The region where the device is located has changed, which generally means that the system language has been switched.
orientation Device rotation, landscape display and portrait display mode switching.
keyboardHidden The accessibility of the keyboard has changed, such as when the user brings up the keyboard.
screenSize When the screen size information has changed. When the device screen is rotated, the screen size changes.
smallestScreenSize The physical screen size of the device changes, this item has nothing to do with the orientation of the screen.

When android:configChanges = “orientation|screenSize” is specified, the screen is rotated, the Activity will not be recreated, and onSaveInstanceState and onRestoreInstanceState are not called to store and restore data. Instead, the system calls the Activity'sonConfigurationChangedmethod, then you can do some special processing of your own.
[Example: The screen rotates when the Activity specifies the configChanges attribute]

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325748498&siteId=291194637