Does the singleTop startup mode really prevent opening activities at the top of the stack multiple times?

We often encounter various bugs in the development process. For example, the test sister tells us that she clicked a button twice quickly due to no operation (or due to lag or something like that) and opens two detail pages, hoping to disable this and open only one detail page.

Click the button quickly to open the Activity in default launch mode multiple times

Let’s start by replicating the scenario where the Activity configuration and button click code are very simple, as shown below:

<activity
    android:name=".kfysts.chapter01.activity.LauncherModeSecondActivity"
    android:launchMode="standard" />
Copy the code

Button click events:

@OnClick(R.id.btn_test1)
public void onBtnTest1Clicked() {
    startActivity(new Intent(this, LauncherModeSecondActivity.class));
}
Copy the code

We quickly click the button three times, the effect is like the picture below:

Let’s look at the task stack information and enter the following command in the terminal to import the data into log.txt:

For those who are not familiar with log redirection, please focus on directing ADB logcat output to a file.

adb shell dumpsys activity activities > log.txt
Copy the code

Open log.txt, let’s look at the task stack information:

ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)
...
    * TaskRecord{1779ff5 #157 A=com.tiny.demo.firstlinecode U=0 StackId=2 sz=7}
      userId=0 effectiveUid=u0a85 mCallingUid=u0a85 mUserSetupComplete=true mCallingPackage=com.tiny.demo.firstlinecode
      ...
      Activities=[ActivityRecord{991bdbe u0 com.tiny.demo.firstlinecode/.MainActivity t157}, ActivityRecord{9eb4346 u0 com.tiny.demo.firstlinecode/.kfysts.AndroidKfystsActivity t157}, ActivityRecord{d4b56c9 u0 com.tiny.demo.firstlinecode/.kfysts.chapter01.AndroidKfystsChapter01Activity t157}, ActivityRecord{ce38d30 u0 com.tiny.demo.firstlinecode/.kfysts.chapter01.activity.LauncherModeEntryActivity t157}, ActivityRecord{704de09 u0 com.tiny.demo.firstlinecode/.kfysts.chapter01.activity.LauncherModeSecondActivity t157}, ActivityRecord{e063635 u0 com.tiny.demo.firstlinecode/.kfysts.chapter01.activity.LauncherModeSecondActivity t157}, ActivityRecord{bd81a7a u0 com.tiny.demo.firstlinecode/.kfysts.chapter01.activity.LauncherModeSecondActivity t157}]
      ...
Copy the code

You can see our LauncherModeSecondActivity opened three times.

Use singleTop to prevent multiple opens

We can’t ignore the bug mentioned by the little sister. For this bug, our first reaction is to make a method to prevent multiple clicks on the View, but here we have a better choice. For clicking to open an Activity, you can use the Activity launch mode — singleTop. The core of this mode is that the Activity at the top of the stack does not create another instance.

SingTop explains as follows:

SingleTop: Top of stack reuse mode. In this mode, if the new Activity is already at the top of the task stack, the Activity is not recreated, and its onNewIntent method is called, with parameters from which we can retrieve the current request information. If an instance of the new Activity already exists but is not at the top of the stack, the new Activity will still be recreated.Copy the code

In the androidmanifest.xml file, add android:launchMode=”singleTop” to the corresponding Activity. The code is as follows:

<activity
    android:name=".kfysts.chapter01.activity.LaunchModeSingleTopTestActivity"
    android:launchMode="singleTop" />
Copy the code

Here is a new log, we can use the log to determine the specific number of clicks.

@OnClick(R.id.btn_test5)
public void onBtnTest5Clicked() {
    LogUtils.e("single Top clicked");
    startActivity(new Intent(this, LaunchModeSingleTopTestActivity.class));
}
Copy the code

We then try clicking the button multiple times and find that the problem of opening the Activity multiple times has been solved.

Let’s look at log. We did click the button multiple times:

com.tiny.demo.firstlinecode E: single Top clicked
com.tiny.demo.firstlinecode E: single Top clicked
com.tiny.demo.firstlinecode E: single Top clicked
Copy the code

Take a look at the effect picture, as follows:

Adb shell dumpsys Activity Activities > log.txt

* TaskRecord{b982558 #158 A=com.tiny.demo.firstlinecode U=0 StackId=3 sz=5}
      userId=0 effectiveUid=u0a85 mCallingUid=u0a85 mUserSetupComplete=true mCallingPackage=com.tiny.demo.firstlinecode
      ...
      Activities=[ActivityRecord{47ddc34 u0 com.tiny.demo.firstlinecode/.MainActivity t158}, ActivityRecord{206fabc u0 com.tiny.demo.firstlinecode/.kfysts.AndroidKfystsActivity t158}, ActivityRecord{fa98f6d u0 com.tiny.demo.firstlinecode/.kfysts.chapter01.AndroidKfystsChapter01Activity t158}, ActivityRecord{a41b176 u0 com.tiny.demo.firstlinecode/.kfysts.chapter01.activity.LauncherModeEntryActivity t158}, ActivityRecord{e2f82e5 u0 com.tiny.demo.firstlinecode/.kfysts.chapter01.activity.LaunchModeSingleTopTestActivity t158}]
Copy the code

Can be seen from the results, LaunchModeSingleTopTestActivity at the top of the stack is only one instance.

Based on the above results, we can conclude that the singleTop startup mode does solve the problem of repeated opening of top-of-stack activities. In the case of multiple clicks, top-of-stack activities are only opened once.

Does singleTop completely prevent opening activities at the top of the stack multiple times?

Although our bug was solved perfectly, as programmers, we still need to work on it.

Here I change the code of the click event to call the code that starts the activity several times in a moment. The code is as follows:

@OnClick(R.id.btn_test6)
public void onBtnTest6Clicked() {
    for(int i = 0; i < 5; i++) { startActivity(new Intent(this, LaunchModeSingleTopTestActivity.class)); }}Copy the code

Then let’s look at the effect:

Nani, I can’t believe I opened more than one.

Take a look at the task stack information:

* TaskRecord{f8d39d #159 A=com.tiny.demo.firstlinecode U=0 StackId=4 sz=9}
      userId=0 effectiveUid=u0a85 mCallingUid=u0a85 
      ...
      Activities=[ActivityRecord{9ed78cc u0 com.tiny.demo.firstlinecode/.MainActivity t159}, ActivityRecord{be3aa3c u0 com.tiny.demo.firstlinecode/.kfysts.AndroidKfystsActivity t159}, ActivityRecord{1654b04 u0 com.tiny.demo.firstlinecode/.kfysts.chapter01.AndroidKfystsChapter01Activity t159}, ActivityRecord{a9084f6 u0 com.tiny.demo.firstlinecode/.kfysts.chapter01.activity.LauncherModeEntryActivity t159}, ActivityRecord{932877f u0 com.tiny.demo.firstlinecode/.kfysts.chapter01.activity.LaunchModeSingleTopTestActivity t159}, ActivityRecord{c4238aa u0 com.tiny.demo.firstlinecode/.kfysts.chapter01.activity.LaunchModeSingleTopTestActivity t159}, ActivityRecord{e751011 u0 com.tiny.demo.firstlinecode/.kfysts.chapter01.activity.LaunchModeSingleTopTestActivity t159}, ActivityRecord{fe1ffe4 u0 com.tiny.demo.firstlinecode/.kfysts.chapter01.activity.LaunchModeSingleTopTestActivity t159}, ActivityRecord{c0d8413 u0 com.tiny.demo.firstlinecode/.kfysts.chapter01.activity.LaunchModeSingleTopTestActivity t159}]
Copy the code

As you can see, our LaunchModeSingleTopTestActivity really opened the five times.

This is easy to understand. Any operation takes time to execute, and so does the startup of our activity.

Even if we set the startup mode for our Activity, they do not take effect immediately and only after the corresponding code logic is executed.

So if I start the Activity multiple times in a moment inside the for loop, the code for boot mode hasn’t been executed yet, so the boot mode won’t take effect.

Of course, this is not usually written in code, but knowing what it is and why is our goal.

Github project address :Android_Base_Demo

Specific page opening path:

Specific page address: github.com/tinyvampire…

reference

Android development art exploration