singleTop啟動(dòng)模式真的可以防止多次打開棧頂?shù)腁ctivity么?

singleTop啟動(dòng)模式真的可以防止多次打開棧頂?shù)腁ctivity么?

開發(fā)過程中我們經(jīng)常會(huì)遇到各式各樣的bug,比如說測(cè)試小姐姐告訴我們,由于無操作,某個(gè)按鈕她快速點(diǎn)擊了兩次(或者由于卡頓之類的延遲),打開了兩個(gè)詳情頁(yè),希望把這個(gè)禁止掉,只讓打開一個(gè)詳情頁(yè)。

快速點(diǎn)擊按鈕,多次打開默認(rèn)啟動(dòng)模式的Activity

我們先來復(fù)現(xiàn)下這種場(chǎng)景,Activity配置和按鈕點(diǎn)擊代碼很簡(jiǎn)單,如下所示:
activity配置:

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

按鈕的點(diǎn)擊事件:

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

我們快速點(diǎn)擊三下按鈕,效果大概如下圖所示:

image

我們看下任務(wù)棧信息,在終端中輸入如下命令,將數(shù)據(jù)導(dǎo)入到log.txt中:

不了解日志重定向的同學(xué),請(qǐng)看重定向adb logcat輸出到文件.

adb shell dumpsys activity activities > log.txt

打開log.txt,我們看下任務(wù)棧信息:

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}]
      ...

可以看到我們的LauncherModeSecondActivity打開了三次。

使用singleTop進(jìn)行防止多次打開

小姐姐提的bug我們不能不管,針對(duì)這個(gè)bug我們第一反應(yīng)是做一個(gè)防止View的多次點(diǎn)擊,不過這里我們有更好的選擇。針對(duì)點(diǎn)擊打開Activity這種操作,可以使用Activity啟動(dòng)模式——singleTop來解決,這種啟動(dòng)模式的核心就是,位于棧頂?shù)腁ctivity不會(huì)再次創(chuàng)建實(shí)例。

singTop的解釋如下:

singleTop:棧頂復(fù)用模式。

在這種模式下,如果新Activity已經(jīng)位于任務(wù)棧的棧頂,那么此Activity不會(huì)被重新創(chuàng)建,同時(shí)它的onNewIntent方法會(huì)被調(diào)用,通過此方法的參數(shù)我們可以取出當(dāng)前請(qǐng)求的信息。

如果新Activity的實(shí)例已存在但不是位于棧頂,那么新Activity仍然會(huì)重新創(chuàng)建。

話不多說,我們使用singleTop模式來優(yōu)化下,在AndroidManifest.xml文件中,給對(duì)應(yīng)的Activity添加android:launchMode="singleTop",代碼如下:

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

點(diǎn)擊啟動(dòng)的代碼如下:
這里新增了一條log,我們可以通過log來確定具體點(diǎn)擊了幾次。

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

然后我們嘗試多次點(diǎn)擊按鈕,會(huì)發(fā)現(xiàn)多次打開Activity的問題已經(jīng)解決了。

先看下log,我們確實(shí)多次點(diǎn)擊了按鈕:

com.tiny.demo.firstlinecode E: single Top clicked
com.tiny.demo.firstlinecode E: single Top clicked
com.tiny.demo.firstlinecode E: single Top clicked

再看下效果圖,如下圖:

image

再來看下具體的任務(wù)棧信息,執(zhí)行adb shell dumpsys activity activities > log.txt,結(jié)果如下:

* 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}]

從結(jié)果中可以看到,LaunchModeSingleTopTestActivity在棧頂確實(shí)只有一個(gè)實(shí)例。

綜合以上的結(jié)果,我們可以得出結(jié)論,singleTop啟動(dòng)模式確實(shí)解決了棧頂Activity重復(fù)打開的問題,在多次點(diǎn)擊的情況下,棧頂Activity只打開了一次。

singleTop真的能完全防止多次打開棧頂?shù)腁ctivity么?

雖然我們的bug完美解決了,但作為程序員,我們還是需要杠精下的。

這里我改下點(diǎn)擊事件的代碼,瞬間多次調(diào)用啟動(dòng)activity的代碼,代碼如下:

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

然后我們看下效果:

image

納尼,竟然打開了多個(gè)。

再看下任務(wù)棧信息:

* 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}]

可以看到,我們的LaunchModeSingleTopTestActivity確實(shí)打開了五次。

其實(shí)這也很好理解,不管任何操作都是需要時(shí)間去執(zhí)行的,我們的activity的啟動(dòng)過程也是。

即使我們給Activity設(shè)置了啟動(dòng)模式,他們也不是立刻生效的,也需要執(zhí)行到對(duì)應(yīng)的代碼邏輯后才會(huì)生效。

所以如果我在for循環(huán)里面瞬間執(zhí)行多次打開Activity的操作,那么啟動(dòng)模式生效的代碼還未執(zhí)行到,所以啟動(dòng)模式就不會(huì)生效。

當(dāng)然了,代碼中一般也不會(huì)這么寫,知其然并知其所以然才是我們的目的。

github項(xiàng)目地址:Android_Base_Demo

具體頁(yè)面打開路徑:

image

具體頁(yè)面地址:https://github.com/tinyvampirepudge/Android_Base_Demo/blob/master/app/src/main/java/com/tiny/demo/firstlinecode/kfysts/chapter01/activity/LauncherModeEntryActivity.java

參考

Android開發(fā)藝術(shù)探索

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容