Android review Notes directory

  1. Chatter task stack, return stack and lifecycle

  2. The life cycle of chatter activities

In this paper, a permanent update address: xiaozhuanlan.com/topic/20694…

The last article talked about the chatter stack, the return stack, and the launch mode. Today we’ll talk about the same life cycle related to activities.

I’m sure you can all talk about the Activity lifecycle backwards. Here is a classic large diagram from Android-Lifecycle, which also includes the Fragment lifecycle diagram.

Since this is a 2014 diagram, note that the call times for onRestoreInstanceState() and onSaveInstanceState() vary slightly from SDK version to SDK version, as discussed later in this article.

directory

  • What does each life cycle do?
  • OnStart/onStop? Or onResume/onPause?
  • How to store and restore UI state?
  • Relationship between an Activity and an application process
  • When will the detection of LeakCanary be triggered?
  • Activity encumbered by SharedPreference

What does each life cycle do?

onCreate()

This is the first lifecycle method of the Activity, and the only action that must be done is setContentView().

SetContentView () does a couple of things:

  1. Create a DecorView and set up the PhoneWindow
  2. Parse the XML layout file, generate a View object and stuff it into the DecorView

The DecorView is not drawn, the Window object is not displayed on the screen, and the Activity is not visible.

In addition, developers usually do some data initialization in the onCreate() method.

OnCreate () is called back only once in a full life cycle, and it is not a persistent state; it only enters onStart() after completing the work.

onStart()

OnStart () is also not a persistent state, and the official documentation describes it like this:

The onStart() call makes the activity visible to the user, as the app prepares for the activity to enter the foreground and become interactive.

In the onStart() method, the Activity is visible to the user and the application is ready to come forward to interact with the user. I have a big problem with this Activity being visible to users.

Start an Activity normally, onCreate -> onStart, regardless of the special case.

This is explained in detail in the onResume section below, so you can ponder it first.

What can you do in the onStart() method? It is usually paired with onStop() to do some resource application and release work, such as camera application and release.

onResume

As readers familiar with the UI drawing process know, onResume() is where the UI is actually drawn and displayed. The core logic is WindowManager. AddView () method, the actual call is WindowManagerGlobal addView () method. It does a few things:

  1. Create the ViewRootImpl object
  2. Call the viewrootimpl.setView () method

The ViewRootImpl constructor does a few things:

  1. Initialize the WIndowSession object that communicates with WMS, which is a Binder object
  2. Initialize the Choreographer object

The viewrootimpl.setView () method does several things:

  1. Call the requestLayout() method to initiate the drawing
  2. Binder calls the wms.addtodisplay () method to add the window to the screen

The familiar measurement, layout, and drawing process is done in the requestLayout() method, but not directly, relying on the Vsync signal. RequestLayout () simply registers listening through the Choreographer object that has been initialized previously, and when the next vsync signal comes, the performTraversals() method is called back, where the measurement, layout and drawing actually takes place.

The whole UI drawing process is a lot of knowledge, only by the above simple paragraph of text is certainly not completely summarized, interested readers can go to their own source. But we can be sure that onResume is the time when the real user interface is visible.

So back to the question, what is visible in onStart? I can’t answer this question either, or perhaps everyone is misinterpreting the official documentation to mean “Activity will be visible soon.” You can share your thoughts in the comments section.

Similarly, onResume() can often be used with onPause() to apply and release resources. So, since onStart/onStop and onResume/onPause both work, how do I choose? I’ll do that again later.

onPause

OnPause () is a short process, after which onResume is called back if the user returns to the previous Activity. If not, onStop is called back.

To give onPause an accurate description, it should be non-foreground, non-interactive, but not necessarily invisible. For the system, no matter mobile phone or PC, there must be only one active window in the foreground at the same time, which can obtain focus and interact with the user. Therefore, it is easy to understand that the non-foreground can not interact with the user. It doesn’t have to be invisible how do you understand it? In fact, it is also very simple, similar to PC multi-window, Android system is also multi-window mode.

Finally, note that heavy time consuming operations are not recommended in onPause, because during an Activity jump, the onPause() of the previous Activity occurs before any life cycle of the subsequent Activity.

onStop

A state of complete invisibility. But the Activity is still in memory, just not associated with any Windows. If there is a chance to return later, onRestart -> onStart is called back.

onDestroy

If onStop is not retrieved by the user, it will eventually be destroyed. An active call to Finish or a system configuration change can also cause destruction.

Be careful to release all unwanted resources in onDestroy, otherwise memory leaks may occur.

So far, a brief introduction to the timing of callbacks and what to do in each lifecycle has been provided, along with some questions. Here are some ideas.

OnStart/onStop? Or onResume/onPause?

When using EventBus, you need to register and unregister in the corresponding declaration cycle, as shown below:

@Override
public void onStart(a) {
    super.onStart();
    EventBus.getDefault().register(this);
}

@Override
public void onStop(a) {
    super.onStop();
    EventBus.getDefault().unregister(this);
}
Copy the code

Of course, there is no problem with onResume/onPause.

@Override
public void onResume(a) {
    super.onStart();
    EventBus.getDefault().register(this);
}

@Override
public void onPause(a) {
    super.onStop();
    EventBus.getDefault().unregister(this);
}
Copy the code

But they are not without distinction. Normally, onPause is immediately followed by an onStop, but considering the new multi-window mode added to Android 7.0, the Activity may stay on onPause for a while. In this case, if the resource is released in onStop, it may not be released in time. If your Activity holds a system resource such as the camera, other applications will not be able to use the resource, which is definitely unfriendly to users. So, consider the application scenario when doing something like this. OnResume /onPause focuses on whether the Activity can interact, and onStart/onStop focuses on whether the Activity is visible.

Finally, coupling the LifeCycle processing to the view controller in the above code is not very elegant and can be decoupled through the LifeCycle component. Here’s the code from my previous article:

class LocationUtil() :LifeCycleObserver {
  @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
  fun startLocation( ){... }@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
  fun stopLocation( ){... }}Copy the code

Portal:

Core explains Jetpack’s LifeCycle tutorial

Core LifeCycle for Jetpack

How to store and restore UI state?

In addition to persistent storage of data under normal conditions, data preservation and recovery under abnormal conditions are also necessary. The exceptions here generally refer to system configuration changes, typical horizontal and vertical screen switching, system language switching, etc.

The onSaveInstanceState() method is called to save the current state of an Activity that is terminated in an abnormal case. So which states are saved by default? We can look at TextView’s onSaveInstanceState() method.

@Override
public Parcelable onSaveInstanceState(a) {
    Parcelable superState = super.onSaveInstanceState(); .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);
                }
                // Save the text
                ss.text = sp;
            } else{ ss.text = mText.toString(); }}...return ss;
    }

    return superState;
}
Copy the code

You can see that the text is saved, there’s a lot of code being cut out here, and there’s actually some other state being saved as well. Any View that implements the onSaveInstanceState() method is saved. When an Activity is recreated, the state is restored using the onCreate() or onRestoreInstanceState() methods.

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
}

override fun onRestoreInstanceState(savedInstanceState: Bundle) {
    super.onRestoreInstanceState(savedInstanceState)
}
Copy the code

Overwriting the two methods in Kotlin also shows that the argument to the onCreate() method is nullable because of normal startup conditions. Therefore, it is recommended to restore the status directly in the onRestoreInstanceState method.

For other data that is not in the UI state, you have to manually save and restore it yourself. Here is the sample code for the official documentation:

override fun onSaveInstanceState(outState: Bundle?) {
    // Save the user's current game stateoutState? .run { putInt(STATE_SCORE, currentScore) putInt(STATE_LEVEL, currentLevel) }// Always call the superclass so it can save the view hierarchy state
    super.onSaveInstanceState(outState)
}qubie

override fun onRestoreInstanceState(savedInstanceState: Bundle?) {
    // Always call the superclass so it can restore the view hierarchy
    super.onRestoreInstanceState(savedInstanceState)

    // Restore state members from saved instancesavedInstanceState? .run { currentScore = getInt(STATE_SCORE) currentLevel = getInt(STATE_LEVEL) } }Copy the code

Note that storing data by onSaveInstanceState is not recommended because it happens on the main thread and has serialization/deserialization overhead. A better approach is to use a ViewModel, which can hold data during Activity rebuilding as system configuration changes occur.

Finally, call timing of onSaveInstanceState. This timing is not unique across different SDK versions.

  • Before SDK 11, inonPause()Before the call
  • Prior to SDK 28, there will beonStop()Before the call
  • After SDK 28, there will beonStopAfter the call

Of course, it doesn’t really make any difference to us.

Relationship between an Activity and an application process

Are individual activities directly reclaimed by the system when the system is out of memory?

The answer is no.

First, the lifetime of the application process is not directly controlled by itself, but determined by the system. Every App has at least one Linux process. When the system runs out of memory to meet the needs of the process that is interacting with the user, some resources may be reclaimed. These resources are process-by-process, not process-by-process components, and no individual Activity is reclaimed by the system.

So, if you want to recycle a process, you must divide it into three, six, five, and so on. According to the official document, there are roughly these categories, in descending order of importance.

Foreground Process :

  • There is an Activity in the foreground, interacting with the user
  • BroadcastReceiver’s onReceive method is executing
  • Service is running code, including onCreate, onStart, and onDestroy

The Visible Process:

  • The Activity is visible, but not in the foreground
  • Service is running foreground services
  • Hold some user-aware specific services, such as dynamic wallpaper, input method services

The Service Process:

There are running services that are not visible to the user but are performing tasks that the user cares about, such as background downloads. When the system runs out of memory, it can get bumped.

The official article says that running more than 30 minutes may be degraded, but there is definitely a magic change in different domestic ROMs, the specific should be based on the actual test.

Cached Process:

A useless thread that can be terminated at any time when the system runs out of memory. However, in order to switch applications more efficiently, the system will not kill them all.

When will the detection of LeakCanary be triggered?

Codelang, our friend in the group, shared an interesting knowledge point:

Why does LeakCanary call refwatcher.watch () after Activity onDestroy to start monitoring for memory leaks?

His answer:

From an ActivityThread’s point of view, an Activity is an object. According to GC Root, an Activity is referred to by an ActivityThread. The reason for starting detection after onDestroy is that the Activity and ActivityThread references are broken at this point, In ActivityThread. PerformDestroyActivity () was removed from the mActivities current Activity object.

Indeed, before onDestroy(), the Activity didn’t break references to GC Roots at all, detecting nothing.

Activity encumbered by SharedPreference

Previously, I wrote an article detailing the slot points of SharedPreference to poke fun at SP. Improper use of SP may result in stalling or even ANR.

The Apply () method differs from the commit() method in that it uses asynchronous tasks to perform storage operations, implemented through the QueuedWork class.

QueuedWork.queue(writeToDiskRunnable, ! isFromSyncCommit);Copy the code

In onStop, you wait for the asynchronous task to complete. Take a look at the handleStopActivity() method in ActivityThread.java:

@Override
public void handleStopActivity(IBinder token, boolean show, int configChanges,
        PendingTransactionActions pendingActions, boolean finalStateRequest, String reason) {...// There may be a lag or even an ANR due to waiting for writes
    if(! r.isPreHoneycomb()) { QueuedWork.waitToFinish(); }... }Copy the code

No matter what data is modified, the storage is written in full. If the amount of data is too large, performance problems will definitely occur. In addition, it should be noted that the comfort process of SP is also full read and put into memory, so in the case of large data, pay attention to the initialization in advance.

The last

So much for the Activity lifecycle, and I’ll come back later if I have any interesting questions about it.


See this, might as well pay attention to me!