Activity is the most important component in common App development. It is mainly used to display interface and user interaction. This paper is divided into three parts:

Activity source code and FAQ

  1. The Activity lifecycle, normal and abnormal?
  2. The Activity of the four start mode, start page setup singleTask/singleInstance can cause what consequence?
  3. What are task, task stack, foreground task stack, background task stack, and return stack respectively?
  4. A series of problems caused by startActivityForResult?
  5. Clearing the back stack of some concepts
  6. The use of allowTaskReparenting
  7. The implicit start of an Activity
  8. Activity Startup process

Deep problems in Activity

  1. How do changes to the Activity lifecycle affect the priority of the process?
  2. If the App has a caching process, will the onCreate method of the Application execute when you start the App?
  3. Why does one Activity start another Activity B with onPause (A) and onStop (B) after onResume (B)?
  4. Why design the Activity lifecycle this way?

Some Activity Settings in third-party apps

  1. Toutiao Speed Edition – News interface opens some restrictions and home page

Activity source code and FAQ

1. The Activity lifecycle, normal and abnormal?

First, take a look at the Activity lifecycle on the official website, as shown in the figure below

Life cycles are often used in development, such as callbacks to specific methods such as recovery and destruction in the interface, where we do some data processing, etc. Missing are the onSaveInstance and onRestoreInstance methods for state saving and restoration, and the onConfigurationChanged() method for callbacks after configuration changes.

Here are some common lifecycle callback flows:

  • Start the Activity: onCreate()->onStart()->onResume()

  • OnPause ()->onStop()->onDestroy()

  • Click the Home button onPause()->onSaveInstanceState()->onStop(). Note that onSaveInstanceState() is executed after the API28.

  • The user returns to the original Activity: onRestart()->onStart()->onResume()

  • A Activity starts B Activity: A#onPause()->B#onCreate()->B#onStart()->B#onResume()->A#onStop()

Take a look at life cycle analysis in exceptional cases:

  1. Lifecycle callbacks to system configurations when configuration changes occur (API28+)

    OnPause () – > onStop () – > onSaveInstanceState () – > onDestroy (), Then execute onCreate()->onStart()->onRestoreInstanceState()->onResume() when the Activity is recreated.

    The configuration changes here can mean rotating the screen or switching to multi-window mode, etc.

    If you don’t want to re-create your Activity when the system configuration changes, you can configure the Android :configChanges property in androidmanifest.xml. If you want to do something extra, you can do it in the onConfigurationChanged callback.

  2. Low priority processes are reclaimed due to insufficient resource memory. When system resources are insufficient, low priority processes are killed. In this case, onSaveInstanceState() and onRestoreInstanceState() are called to store and restore data.

2. The Activity of the four start mode, start page setup SingleTask/SingleInstance can cause what consequence?

When you declare an Activity in a manifest file, you can use the launchMode attribute of the Activity element to specify how the Activity should be associated with the task.

  • Stardard: Default mode in which the system creates a new instance of the Activity in the task that starts the Activity and delivers the intent to the instance. An Activity can be instantiated multiple times, each instance belonging to a different task, and each task can have multiple instances. Note that FLAG_ACTIVITY_NEW_TASK and FLAG_ACTIVITY_CLEAR_TOP will be recreated in this mode, either alone or together.

  • SingleTop: If an instance of an Activity already exists at the top of the current task, the system forwards the intent to that instance by calling its onNewIntent() method, rather than creating a new instance of the Activity. If FLAG_ACTIVITY_CLEAR_TOP is used in this mode, the instance will not be recreated and will have a singletask-like effect, but if FLAG_ACTIVITY_NEW_TASK is used, a new instance will be created.

  • SingleTask: In stack reuse mode, the system will create a new task and instantiate the root Activity of the new task. However, if an instance of the Activity already exists in another task, the system forwards the intent to the existing instance by calling its onNewIntent() method, rather than creating a new one. Only one instance of an Activity can exist at a time. This mode has the effect of clearTop by default.

  • SingleInstance: Single-instance mode, similar to “singleTask” except that the system does not start any other activities into the task containing the instance. The Activity is always the only member of its task; Any activities that are started by this Activity are opened in other tasks.

    There is A special case for singleInstance. If an Activity (Standard) starts Activity B (singleInstance), the user clicks the phone’s recent access list and then clicks the interface (card) where the App is located. Then, clicking the back button at this time will directly exit the App instead of returning to the AN Activity interface as we expected. In fact, the recently visited list is also an Activity (let’s say C Activity). When we click the App card from this C Activity to display the interface B where our singleInstance is located, this is equivalent to C starting B, so we click the back button. I went straight back to the desktop (interested in looking at the source code).

    There is also a special case (from the article of throwline leader) where a Task seen in a recent quest is not necessarily alive, and a Task not seen in a recent quest is not necessarily dead, such as singleInstance. When we look at recent tasks, different tasks are displayed side by side, but there is one prerequisite: their taskAffinity needs to be different. On Android, multiple tasks can be created with the same taskAffinity, but only one of them can be displayed in the most recent Task list. This is why the singleInstance Activity in the previous example is missing from the most recent Task: it was prioritized by another Task with the same taskAffinity.

    In the same way, you are in an App from the home page Activity to create a new Activity (singletask/singleInstance), if you don’t specify taskAffinity, this Activity’s taskAffinity and other interface, So in the most recent range list, you can only see one App card, but if you set taskAffinity differently, you can see two apps in the most recent list.

The task described above corresponds to the TaskRecord(stack structure), which maintains an ArrayList

to store and manage activityRecords. ActivityRecord contains all information about an Activity.

Usually our App will set up the launch screen (usually a picture) and then go to our main screen (MainActivity). There is a lot of logic in the main screen that causes the screen to be extremely large and take up a lot of memory. So most of the time we will set the interface to SingleTask in-stack reuse mode.

Scene 1: If in order to achieve quick start, will our splash screen page of the App (SplashActivity shows fixed picture) remove, change MainActivity (SingleTask/SingleInstance) background (windowBackground), Finally, it is replaced with the theme of App to give users a quick response experience;

Scenario 2: if the page to start the SplashActivity set for SingleTask/SingleInstance mode, at the same time you start page not timely shutdown.

The above two scenarios will cause your App to start from the startup page every time you click the icon, regardless of cold startup or hot startup. The specific principle can be found in the analysis and solution of this article. Remember, don’t in your App SingleTask/SingleInstance startup interface Settings.

3. What are task, task stack, foreground task stack, background task stack and return stack respectively?

Understand Tasks and Back Stack, (A task is a collection of activities that users interact with when performing a certain job. The activities are Arranged in a stack — the back stack (in the order in which each activity is opened.) A task is a collection of activities that a user interacts with while performing a task. The activities are arranged in a return stack in the order in which each Activity was opened. The task corresponds to a TaskRecord(stack structure), which maintains an ArrayList

to store and manage activityRecords. ActivityRecord contains all information about an Activity. So a task is a stack of tasks (a TaskRecord is a stack structure).

So what is the return stack, showing a Gityuan blog firstThe picture.

  • Generally, ActivityStackSupervisor and ActivityDisplay are system unique in the absence of split screens and virtual screens.
  • ActivityDisplay consists of two stacks: Home Stack and App Stack.
  • There can be several TaskRecord objects per ActivityStack, and there is currently only one ActivityStack that is in focus;
  • Each TaskRecord contains several ActivityRecord objects;
  • Each ActivityRecord records one Activity.

A return stack may contain only one task, but in special cases, multiple tasks may be introduced. This concept is very important. Here is the official chart

ActivityX, ActivityY, Activity1, Activity2. ActivityY, ActivityX (both SingleTask) in background tasks, Activity2, Activity1 in foreground tasks, these two tasks have different taskAffinity. When launching ActivityY from Activity2, Return to the stack as shown in the second column, and then click the back key to exit one by one.

One more general concept: In Android, each Activity has a taskAffinity, which acts as a pre-group for each Activity. Its value is taken by default from the taskAffinity of the Application in which it resides, and the taskAffinity of the Application defaults to the package name of the App. You can also specify taskAffinity manually.

Activity1 is not specified in the figure. In fact, I wouldn’t be able to simulate this scenario if we set it to standard mode. This is a bit of a mess because the four activities are ranked 2,1, X, and Y, which means that they start from Y, X, 1, If Activity1 is standard, it does not matter if you specify a different taskAffinity for Activity1 than for ActivityY. Activity1 will still be in the same TaskRecord as ActivityY. That is, the standard and singleTop activities are launched in a TaskRecord depending on which TaskRecord the Activity is launched in. TaskAffinity only makes sense if it is specified in singleTask mode at the same time (with the exception of Standard and singleTop when allowTaskReparenting is true and is evoked by other apps in DeepLink mode). Will be in the assigned task).

Therefore, we set Activity2 and Activity1 as singleTask and taskAffinity as the same to simulate the above scenario. Click Activity2 to activate ActivityY, and the background task stack ActivityY will be added. ActivityX goes all the way to the foreground task stack, which means all the way to the back stack.

summary

An ArrayList

is used to store and manage activityRecords. ActivityRecord contains all information about an Activity.

A return stack may contain only one task, but in special cases, multiple tasks may be introduced. Return stack, foreground task stack, background task stack in fact, there is no clear definition in the source code, but in our operation task stack process put forward some “concepts”, in order to facilitate the description and distinction.

The foreground stacks, such as Activity2 and Activity1 in figure A, and the background stacks, are ActivityY and ActivityX.

The problem is that when Activity2 starts ActivityY, the stack is returned as shown in Figure B below. What is the foreground stack?

At this point, the background task stack (ActivityY, ActivityX) has been returned to the foreground, all four activities are in the foreground, and the back stack contains all the activities that have been transferred to the foreground task (this sentence is from the description of this scenario on the website).

For example, the background task stack is waiting for the recovery of ActivityX, ActivityY, Activity1, Activity2. If you don’t do anything at this time, you keep hitting back. The four activities will exit one by one. At this point, will you feel that the return stack contains the foreground task stack and the background task stack? In figure A, the Back Stack only indicates Activity1 and Activity2, which is contradictory. But I feel that the Back Stack is literally what it means. How many activities can you exit by clicking the Back button? The return stack is a concept, but you can also understand that its size changes dynamically (it may be increased by clicking the return key).

4. A series of problems caused by startActivityForResult?

When you start a new interface using the Activity’s startActivityForResult, activity.result_canceled is returned after the Api20 adjustment, which officials feel should not be setResult between tasks. In Api20 and above, for non-startActivity jumps, i.e., reqeusetCode>=0, activities launched in singleTask and SingleInstance modes do not create a new task and remain in the original stack. Officials also recommend:

Though all Activity class API level provides the underlying [startActivityForResult ()] (developer.android.com/reference/a… , int)), and [onActivityResult ()] (developer.android.com/reference/a… , int, android.content.intent) API, However, we strongly recommend you use the Activity Result API introduced in AndroidX Activity 1.2.0-Alpha02 and Fragment 1.3.0-alpha02.

5. Clear the back stack of some concepts

If the user is away from the task for a long time, the system clears all activities in the task except the root Activity. When the user returns to the task again, only the root Activity resumes. The system behaves this way because, after a period of time, the user may have abandoned the previous action and now return to the task in order to start something new.

You can modify this behavior using some Activity properties:

  • alwaysRetainTaskState

    If you set this property to “true” in the root Activity of the task, the above default behavior will not occur. Even after a long period of time, a task keeps all activities in its stack.

  • clearTaskOnLaunch

    If you set this property to “true” in the root Activity of the task, the stack will be cleared to the root Activity as soon as the user leaves the task and returns. That is, it is the opposite of waysRetainTaskState. Users always return to the initial state of the task, even if they leave it briefly.

  • finishOnTaskLaunch

    This property is similar to clearTaskOnLaunch, but it only works on a single Activity, not the entire task. It can also cause any Activity to disappear, including the root Activity. If this property is set to “true”, the Activity only belongs to the task in the current session. If the user leaves the task and returns, the task no longer exists.

6. The use of allowTaskReparenting

An Activity by default belongs to only one Task and does not jump between tasks, but you can change this logic by setting it. Set its allowTaskReparenting attribute to true. If not set, the value set by the corresponding allowTaskReparenting attribute of the

element. The default value is false.

Normally, an Activity starts in association with the task that started it and remains at that task for its entire life cycle. You can use this property to force an Activity to change its parent to a similar task when an existing task is no longer displayed. This property is typically used to move an application’s Activity to the main task associated with the application.

For example, if an E-mail message contains a link to a web page, clicking on that link brings up an Activity that displays that page. The Activity is defined by the browser application but starts as part of an email task. If you change the parent of the Activity to a browser task, it will show up the next time the browser comes to the foreground and disappear the next time the email task comes to the foreground.

7. Implicit start of Activity

Activities are classified into display start and implicit start. Display start is the startActivityXXX() method we usually call. Implicit start can be started by action. At the same time, remember to add a category for “android. Intent. The category. The DEFAULT”.

Intent implicitIntent = new Intent();
implicitIntent.setAction("com.test.image");
implicitIntent.addCategory("android.intent.category.DEFAULT");
MainActivity.this.startActivity(implicitIntent);
Copy the code

The configuration of the interface is as follows:

<activity android:name=".ImageActivity"
    android:exported="true">
    <intent-filter>

        <action android:name="android.intent.action.MAIN" />
        <action android:name="com.test.image" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>
Copy the code

Android: Exported =”true” to invoke an Activity from another App.

8.Activity startup process (Intermediate questions)

This can be a daunting question for many developers, simply because it’s a bad answer, because there’s a lot of stuff involved and it requires a lot of knowledge. Let’s try to answer this question (based on source 9.0)

Let’s start with some common concepts

Instrumentation

Android Instrumentation is a set of control methods or “hooks” in the Android system, these hooks can be in the normal life cycle (normal is controlled by the operating system) to control the operation of Android controls, In fact, refers to the Instrumentation class to provide a variety of process control methods.

App -> Instrumentation -> AMS -> APP, automated testing can operate activities through instrumentation, the instrumentation is equivalent to the design of a unified entrance.

ActivityThread

Activitythreads are not threads, but instead run in the ActivityThread.main() method, which is the entry point for android applications, and where a Looper iterates through the message queue. Manages the execution of the main thread in the application process, scheduling and executing activities, broadcasts, and related operations according to the request of the Activity manager.

public static void main(String[] args) {
    // One of the most important aspects of reading source code is the ability to 'see only you'...// Create the main thread Looper object, found that the worker thread Looper object call method is not the same.
    // The main thread also has Looper objects
    Looper.prepareMainLooper();

    / / create ActivityThread
    ActivityThread thread = new ActivityThread();
    thread.attach(false);

    // If the main thread's Handler is empty (as you can see how readable a good name is), create a Handler for the main thread.
    // We can also create handlers on the main thread to indicate that there are multiple handlers for one thread. Read the source code, a lot of problems have been solved.
    if (sMainThreadHandler == null) { sMainThreadHandler = thread.getHandler(); } stars. The loop ();// There is an exception. The main thread loop exits abnormally. The main loop cannot exit the Looper object
    throw new RuntimeException("Main thread loop unexpectedly exited");
}
Copy the code
ActivityManagerService

The most core service in Android is mainly responsible for the startup, switching, scheduling of the four major components of the system and the management and scheduling of applications.

ActivityManager

This class provides information and interaction methods related to activities, services, and processes and can be considered a helper class to ActivityManagerService.

ActivityStackSupervisor

Manage all Activity stacks. MHomeStack, mFocusedStack and mLastFocusedStack are internally managed. MHomeStack manages the Launcher related Activity stack. MFocusedStack manages the Activity stack currently displayed in the foreground Activity; MLastFocusedStack manages the Activity stack from which the Activity was last displayed in the foreground. Below is a general diagram. ActivityStackSupervisor and ActivityDisplay are system unique in the absence of split screens and virtual screens.

ActivityStack

ActivityStack is responsible for the state and management of the Activity stack. ActivityStack contains multiple task records. TaskRecord maintains an ArrayList

to store and manage ActivityRecords. ActivityRecord contains all information about an Activity

If we click to start the app from the desktop, the desktop is an Activity, and click the app (button) to start our Activity on the start page. It is more comprehensive to analyze the start process of the Activity from here, instead of starting a common Activity in the app. It can be divided into the following processes

  1. The Launcher notifies AMS to start the Activity of the App’s startup page. AMS records the information about the Activity to be started and notifies THE Launcher to enter the pause state.

    When the Launcher enters the pause state, AMS is notified that paused has been implemented and the App can be started

  2. If the App is not enabled, AMS sends a request to create a process. Zogyte receives the request and incubates the application process. The application process calls ActivityThread and calls mian(), and the main() method creates an ActivityThread object. Bind (the application process binds to AMS) in the ActivityThread.attach () method and pass in the applicationThread for communication.

  3. AMS tells the App to bindApplication (bindApplication), start the Activity, create and associate the Context, and finally call methods such as onCreate.

How to communicate with AMS, Zogyte, App process and Launcher?

This question, once asked, can turn over a lot of developers. Here’s a closer look:

How do App processes and AMS communicate?

Zogyte forks an App process, and it’s a matter of apps and AMS. As we know, Android’s cross-process communication is served by Binder, and AMS’s processes and apps actually communicate with each other through their proxy classes.

ActivityManagerService(AMS) starts when the phone is turned on. Application processes that call AMS methods, such as startActivity, are easy to call because AMS is a named Binder service, You can query the proxy class in ServiceManger (SM) anywhere, call the corresponding method of the proxy class, and then call the real AMS method.

Because Binder communicates through proxy class, if it can’t get the proxy class, other processes don’t know how to communicate with our App, so does AMS in the system service. Therefore, after the App process is created, the proxy will be set. The setting process of proxy is shown in the figure

In the ActivityThread.attach(false) method, AMS binds the ApplicationThread object, that is, the application process binds to AMS, By calling AMS attachApplication, bind the internal class ApplicationThread object of ActivityThread to AMS so that AMS can control the application process through this proxy object.

How do AMS and Launcher communicate?

In fact, the Launcher is also an App, call the startActivity method, and then call the execStartActivity method of Instrumentation

public ActivityResult execStartActivity(
        Context who, IBinder contextThread, IBinder token, Activity target,
        Intent intent, int requestCode, Bundle options) {...try{...// Get the AMS proxy object
        intresult = ActivityManager.getService() .startActivity(whoThread, who.getBasePackageName(), intent, intent.resolveTypeIfNeeded(who.getContentResolver()), token, target ! =null ? target.mEmbeddedID : null,
                    requestCode, 0.null, options);
        checkStartActivityResult(result, intent);
    } catch (RemoteException e) {
        throw new RuntimeException("Failure from system", e);
    }
    return null;
}
Copy the code

This method calls ActivityManager’s getService method to get the AMS proxy object, and then calls the startActivity method of that proxy object

@UnsupportedAppUsage
public static IActivityManager getService(a) {
    return IActivityManagerSingleton.get();
}

@UnsupportedAppUsage
private static final Singleton<IActivityManager> IActivityManagerSingleton =
        new Singleton<IActivityManager>() {
            @Override
            protected IActivityManager create(a) {
                // Get the activity's service reference, which is an AMS reference of type IBinder
                final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
				        // Convert to an IActivityManager object
                final IActivityManager am = IActivityManager.Stub.asInterface(b);
                returnam; }};Copy the code

As you can see in the create method of Singleton, since B is AMS reference as the server in the SystemServer process, it is not in the same process as the current Launcher process as the client and server. Therefore, AM returns the proxy object of iActivityManager. Stub. If you want to realize the communication between the client and the server process, you only need to inherit the iActivityManager. Stub class and implement the corresponding method in AMS. AMS inherits the iActivityManager. Stub class, so that the Launcher process, as the client, has a proxy object for AMS on the server, and can then call AMS methods to implement specific functions. That’s how AMS implements the Launcher.

public class ActivityManagerService extends IActivityManager.Stub
        implements Watchdog.Monitor.BatteryStatsImpl.BatteryCallback {}Copy the code

How do Zygote and AMS communicate?

AMS and Zygote establish a Socket connection and then send a request to create the application process. For details, please refer to here.

Finally, let’s take a look at the flow chart. Look at the App process startup process and activity.startActivity below

It should also be mentioned that the Hook Activity startup process is an important usage scenario. We need to trick AMS and then launch the real TargetActivity. The Hook has a start point and an end point. There are two hooks to look for: replacing an Activity in an Intent (hookIActivityTaskManager) and restoring an Activity in an Intent (hookHandler).

When answering the question of how to start an Activity, the specific method is not important, so I will show the whole process at the end. How to establish communication between processes and how to communicate is important, and some concepts related to activities are also important.

Deep problems in Activity

1. What impact do changes in the Activity lifecycle have on process priorities?

OnStart is visible to the user when the Activity is onStart

You can also find a similar description in Android Development Art Quest

The ActivityThread handleResumeActivity method first calls the Activity’s onResume method. This is followed by a call to activity. makeVisible(), where the DecorView actually adds and displays the Activity’s view. The DecoreView is associated with the Window. If you are interested, take a look at my analysis of this article.

void makeVisible(a) {
        if(! mWindowAdded) { ViewManager wm = getWindowManager();//DecoreView is associated with WindowManager.
            wm.addView(mDecor, getWindow().getAttributes());
            mWindowAdded = true;
        }
  			// Set DecorView visibility
        mDecor.setVisibility(View.VISIBLE);
    }
Copy the code

That is, after the onResume method is executed and then we call the activite.Makevisible () method, we can actually see our DecoreView with the naked eye, and when you look at this, you can’t help but wonder, The onStart() call makes the Activity visible to the user.

With that in mind, we continue to look for answers on the official website, in the section on process and life cycle:

To determine which processes should be killed when out of memory, Android puts each process into an “importance hierarchy” based on the components running in it and the state of those components. These process types include (in order of importance) :

  1. The foreground process is the process that the user currently needs to perform the operation. In different cases, a process may be considered a foreground process because of the various application components it contains. A process is considered foreground if any of the following conditions are true:
  • It’s running one on the user’s interactive screenActivity(theonResume()Method already called).
  • It has oneBroadcastReceiverCurrently running (itsBroadcastReceiver.onReceive()Method executing).
  • It has oneServiceCurrently executing one of its callbacks (Service.onCreate(),Service.onStart()Service.onDestroy()).
  1. There are only a few such processes on the system, and they are terminated at the last step unless memory is so low that even these processes can no longer run. Typically, the device has reached the memory paging state at this point, so you must perform this operation to keep the user interface responsive.

  2. A visible process is performing tasks that the user is currently aware of, so terminating the process has a significant negative impact on the user experience. Processes are considered visible under the following conditions:

    • It’s runningActivityVisible to the user on the screen, but not in the foregroundonPause()Method already called). For example, this might happen if the foreground Activity is displayed as a dialog box that allows the previous Activity to be seen behind it.
    • It has oneServiceIs throughService.startForeground()(requires the system to treat the service as a service that the user knows about or is essentially visible to the user) running as a foreground service.
    • The system is using its hosted services to implement user-aware specific functions, such as dynamic wallpaper, input method services, and so on.

    The number of these processes running in the system is less limited than the foreground process, but is still relatively controlled. These processes are considered so important that they are not killed unless the system needs to kill them in order to keep all foreground processes running.

  3. The Service process contains a Service that has been started using the startService() method. Although these processes cannot be seen directly by the user, they are usually performing tasks that the user cares about (such as background network data uploads or downloads), so the system will always keep them running unless there is not enough memory to hold all foreground and visible processes.

    A service that has been running for a long time (for example, 30 minutes or more) may be downgraded in importance to bring its process down to the cached LRU list described below. This helps to prevent extremely long-running services from taking up large amounts of memory due to memory leaks or other issues that prevent the system from using caching processes efficiently.

  4. A cache process is a process that is not currently needed, so if memory is needed elsewhere, the system is free to kill the process as needed. In a functioning system, these are the only processes involved in memory management: a well-functioning system will always have multiple caching processes available (to switch applications more efficiently) and will periodically terminate the earliest processes as needed. All cache processes in the system are terminated only in critical (and undesirable) situations, at which point the system must begin terminating the service process.

    These processes typically contain one or more Activity instances that are not currently visible to the user (the onStop() method has been called and returned). As long as they implement their Activity lifecycle correctly (see Activity for details), when the system terminates such a process, the user’s experience of returning to the time should not be affected, because when the associated Activity is recreated in a new process, it can restore the previously saved state.

    These processes are stored in a pseudo LRU list, the last of which is the first process to terminate in order to reclaim memory. The exact ranking policy for this list is platform implementation details, but it generally tries to keep more useful processes (such as the process hosting the user’s home screen application, the last Activity the user saw, and so on) before keeping other types of processes. You can also apply other policies for terminating processes: hard limits on the number of processes allowed, limits on how long a process can remain cached, and so on.

You can see that an Activity’s onResume method has been called while it’s running on the screen, and it’s in the foreground process. A condition for a visible process: The Activity it is running is visible to the user on the screen, but not in the foreground, and then compared to the onStart description above (the onStart() call makes the Activity visible to the user, because the application prepares for the Activity to come into the foreground and support interaction), Now you can see that onStart is visible to the visible process, not to the naked eye.

OnPause This method means that the Activity is no longer in foreground (although it is still visible when the user is in multi-window mode). If your Activity is no longer visible to the user, it has entered the “stopped” state, so the onStop() callback will be called. The above is the official description, we can print these processes in the phone, using adb shell dumpsys meminfo command, the device is Android 10 Huawei phone.

We can see our foreground process, visible process, service process and cache process respectively, among which the service process is also divided into A Services and B Services. There’s a lot more to it than that, so if I open my App and hit the home button to go back to the background, it’s Previous process level com.jackie. Testdialog, if I open my App and hit the back button to exit, At this point my App process becomes Cached.

In Android7.0, ADJ uses 100,200,300 and so on. Here are the distinctions based on android9:

ADJ level The values meaning
NATIVE_ADJ – 1000. Native process
SYSTEM_ADJ – 900. Only the system_server process
PERSISTENT_PROC_ADJ – 800. System Persistent Process
PERSISTENT_SERVICE_ADJ – 700. Associated with systems or persistent processes
FOREGROUND_APP_ADJ 0 Foreground process
VISIBLE_APP_ADJ 100 Visible process
PERCEPTIBLE_APP_ADJ 200 Aware of processes, such as background music playback
BACKUP_APP_ADJ 300 The backup process
HEAVY_WEIGHT_APP_ADJ 400 Heavyweight process
SERVICE_ADJ 500 Service process
HOME_APP_ADJ 600 The Home process
PREVIOUS_APP_ADJ 700 Previous process
SERVICE_B_ADJ 800 B Service in the List
CACHED_APP_MIN_ADJ 900 Minimum adj for an invisible process
CACHED_APP_MAX_ADJ 906 Maximum adj for invisible processes

Developers should focus less on keeping things alive and more on optimizing memory, because the system will prioritize processes that consume memory at the same ADJ level. Of course, you can also test the App’s process level manually, but the process can be a bit cumbersome, so please refer to this article.

summary

When there is only one Activity on the screen, it is a visible process when it enters onStart and onPause, it is a foreground process when it enters onResume, it is a background process when it opens and then it is a Previous process when it hits the Home button. If you click the Back button to exit the Activity, This is the caching process; If there are multiple activities (note that only the app enters the foreground from the background task, or clicks the Home button to go back to the background); The Activity at the top of the stack is visible when it enters onStart and onPause, it is visible when it enters onResume, and it is Previous when it clicks the Home button to go back to background.

2. If the App has a cache process, will the onCreate method of the Application be executed when the App is started?

If you click MainActivity on the main screen and click back, the system will execute the onDestory method of MainActivity. At this point, the App process is a cache process. The next time you start the App, you will find that the onCreate method of Application will not execute. Of course, MainActivity’s life cycle will be normal. This is because starting the App from the cache process, the system has already cached a lot of information, and much of the data will not be destroyed. The content initialized in onCreate will still be there for the user to start quickly next time. Using this feature, the initial startup speed of our App is generally 500, 600ms, and the speed of each startup is generally 200, 300ms when there is a cache process after exiting the App, which can improve the startup time of the App to some extent.

It should be noted that many apps will manually call the following code to exit the App when exiting the main interface

System.exit(0);
Copy the code

Once the following code is called, it exits completely without taking advantage of the caching process and losing the optimization that the system provides.

3. If one Activity A starts another Activity B, the onPause method of Activity A is used first and the onStop method of Activity B is used only after the onResume method of Activity B is executed.

If you’ve looked at the first two questions, you probably already have the answer to this one. The reason why mobile phones manage processes with different priorities is to ensure smooth user experience. Clear processes with low priorities and high memory usage in time to ensure sufficient running space for foreground processes. We talked about at the front desk in front of the focus (get) there is only one interface, onPause current process when left at the front desk, and, of course, may also want to carry on some data save, so definitely need a method of execution of the current interface first, then B interface onCreate, onStart, OnResume is the onStop method so that the new screen can be quickly displayed (to get focus) and then go to the old screen A.

Do not perform time-consuming operations in onPause. If you do, the new screen will take a long time to display. Of course, you can’t do time-consuming operations in onStop. As we have tried before, clicking the Home button will execute onStop method. At this time, the App process is in the background process, and the process has a very low priority.

For state saving and restoration, onSaveInstanceState executes before onStop, but not limited to before or after onPause, prior to API28; After API28, the execution time of onSaveInstanceState is determined to be after onStop. OnRestoreInstanceState is determined to execute after onStart.

4. Why design the Activity lifecycle this way

Suppose you design your own interface lifecycle:

  • Interface startup needs to design a method

  • A method is required to render the interface completely

  • A method is required to partially cover the interface/jump to another interface/retreat to the background

  • A method is required when the interface completely exits destruction

So it looks like we only need onCreate, onResume, onPause, and onDestroy, but that’s just a pretty crude callback to the create ~ exit process, but if you look at the IOS UIViewController lifecycle, Looks like a pretty piggy girl

In comparison, even the Android life cycle is a little rough. In fact, it is not all rough. Activities also have a series of onPostXXX methods and onContentChanged, but it is still not as delicate as IOS. In fact, I think, the life cycle of the callback is designed based on scenarios, from the view of display to the destruction of considering different requirements, we need different levels of design, if Android is a very simple system, also won’t realize so many special demand, may only need I say that in front of the four methods is enough, I feel like IOS does a better job of designing the life cycle and being more developer friendly.

Some people might say, well, why should the lifecycle be designed this way, because the interface needs to have a create/destroy process, so onCreate/onDestroy definitely needs to, onStart to be visible, raise the priority of the process, or do something special, OnResume is required when the interface is started or resumed, onPause() is executed when the interface is overwritten by a transparent Activity, and there needs to be a method to save the state or perform special actions, etc. OnStop can save the state. Such a problem is completely a result of backward thinking, can not withstand careful scrutiny, must not from the specific method to push the scene, but should start from the requirements of the scene, remember, all this is the demand or possible demand caused!

Some Activity Settings in third-party apps

Toutiao Speed edition – Some restrictions on opening the news interface

NewDetailActivity is the ordinary news interface we see. You can only open four NewDetailActivity interfaces at most. If more than four interfaces are opened, the earliest NewDetailActivity will be closed.

TaskRecord{8636d7b #6564 A=com.ss.android.article.lite U=0 StackId=282 sz=5} Run #4: ActivityRecord{8794744 u0 com.ss.android.article.lite/com.ss.android.article.base.feature.detail2.view.NewDetailActivity  t6564} Run #3: ActivityRecord{8be5248 u0 com.ss.android.article.lite/com.ss.android.article.base.feature.detail2.view.NewDetailActivity  t6564} Run #2: ActivityRecord{8bd6a09 u0 com.ss.android.article.lite/com.ss.android.article.base.feature.detail2.view.NewDetailActivity  t6564} Run #1: ActivityRecord{87cc383 u0 com.ss.android.article.lite/com.ss.android.article.base.feature.detail2.view.NewDetailActivity  t6564} Run #0: ActivityRecord{8bd6b44 u0 com.ss.android.article.lite/.activity.SplashActivity t6564}Copy the code

SplashActivity and MainActivity interfaces are used to optimize the quick startup and provide users with a sense of instant startup. Remove the original SplashActivity, rename the MainActivity to SplashActivity, and replace the theme.

Then let’s look at its startup mode, which is Standard.

~ » adb shell dumpsys activity | grep SplashActivity                                                             jackie@JackieLindeMacBook-Pro
    baseIntent=Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.ss.android.article.lite/.activity.SplashActivity }
    baseIntent=Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.sina.weibo/.SplashActivit }
    baseIntent=Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=cmccwm.mobilemusic/.ui.base.SplashActivity }
    baseIntent=Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.daimajia.gold/im.juejin.android.ui.SplashActivity }
      Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.ss.android.article.lite/.activity.SplashActivity bnds=[544.149] [796.458] }
      mActivityComponent=com.ss.android.article.lite/.activity.SplashActivity
    mIntent=Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.ss.android.article.lite/.activity.SplashActivity bnds=[544.149] [796.458]} #0 ActivityRecord{8e43505 u0 com.ss.android.article.lite/.activity.SplashActivity t6684} type=standard mode=fullscreen override-mode=undefined  // The startup mode is standard
      intent={act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.ss.android.article.lite/.activity.SplashActivity}
      mActivityComponent=com.ss.android.article.lite/.activity.SplashActivity
      Activities=[ActivityRecord{8e43505 u0 com.ss.android.article.lite/.activity.SplashActivity t6684}]
        Hist #0: ActivityRecord{8e43505 u0 com.ss.android.article.lite/.activity.SplashActivity t6684}
          Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.ss.android.article.lite/.activity.SplashActivity bnds=[544.149] [796.458] }
        Run #0: ActivityRecord{8e43505 u0 com.ss.android.article.lite/.activity.SplashActivity t6684}
    mResumedActivity: ActivityRecord{8e43505 u0 com.ss.android.article.lite/.activity.SplashActivity t6684}
      intent={act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.sina.weibo/.SplashActivity}
      mActivityComponent=com.sina.weibo/.SplashActivity
      intent={act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=cmccwm.mobilemusic/.ui.base.SplashActivity}
      mActivityComponent=cmccwm.mobilemusic/.ui.base.SplashActivity
 ResumedActivity:ActivityRecord{8e43505 u0 com.ss.android.article.lite/.activity.SplashActivity t6684}
  ResumedActivity: ActivityRecord{8e43505 u0 com.ss.android.article.lite/.activity.SplashActivity t6684}
Copy the code

Let’s look at the startup mode of toutiao’s home page. Its home page is called MainActivity, which also uses Standard.

adb shell dumpsys activity | grep MainActivity                                                                                                          jackie@JackieLindeMacBook-
      Intent { flg=0x24008000 cmp=com.ss.android.article.news/.activity.MainActivity (has extras) }
      mActivityComponent=com.ss.android.article.news/.activity.MainActivity
    mIntent=Intent { flg=0x24008000 cmp=com.ss.android.article.news/.activity.MainActivity (has extras) }
     #0 ActivityRecord{8fadec6 u0 com.ss.android.article.news/.activity.MainActivity t6685} type=standard mode=fullscreen override-mode=undefined  // Standard boot mode
     #0 ActivityRecord{9130583 u0 cmccwm.mobilemusic/.ui.base.MainActivity t6681} type=standard mode=fullscreen override-mode=undefined
      Activities=[ActivityRecord{8fadec6 u0 com.ss.android.article.news/.activity.MainActivity t6685}]
        Hist #0: ActivityRecord{8fadec6 u0 com.ss.android.article.news/.activity.MainActivity t6685}
          Intent { flg=0x24008000 cmp=com.ss.android.article.news/.activity.MainActivity (has extras) }
        Run #0: ActivityRecord{8fadec6 u0 com.ss.android.article.news/.activity.MainActivity t6685}
    mResumedActivity: ActivityRecord{8fadec6 u0 com.ss.android.article.news/.activity.MainActivity t6685}
      Activities=[ActivityRecord{9130583 u0 cmccwm.mobilemusic/.ui.base.MainActivity t6681}, ActivityRecord{9822b05 u0 cmccwm.mobilemusic/com.migu.music.ui.local.LocalSongsActivity t6681}]
        Hist #0: ActivityRecord{9130583 u0 cmccwm.mobilemusic/.ui.base.MainActivity t6681}
          Intent { flg=0x10000000 cmp=cmccwm.mobilemusic/.ui.base.MainActivity (has extras) }
        Run #0: ActivityRecord{9130583 u0 cmccwm.mobilemusic/.ui.base.MainActivity t6681}
 ResumedActivity:ActivityRecord{8fadec6 u0 com.ss.android.article.news/.activity.MainActivity t6685}
  ResumedActivity: ActivityRecord{8fadec6 u0 com.ss.android.article.news/.activity.MainActivity t6685}
Copy the code

I looked for the scene of clicking a button from a certain interface to return to the home page in Toutiao and toutiao Speed app, but found no such scene, or very few (maybe I did not find it). As mentioned above, a new instance will be created every time when the standard mode is started. If there are many scenes where other interfaces return to the home page, I think singleTop may be used (flag can be used to achieve the effect similar to SingleTask). Few or no scenarios is why it uses Standard.

At this point, we have finished the introduction and analysis of Activity, like a like and pay attention to it.

The last:

Do you understand Handler’s basic, intermediate, and advanced questions?

Refer to the article

Android Development Art Exploration

Developer.android.com/guide/compo…

Juejin. Cn/post / 689191…

Juejin. Cn/post / 688374…

Juejin. Cn/post / 684490…