singleTop啓動模式真的能夠防止屢次打開棧頂的Activity麼?

singleTop啓動模式真的能夠防止屢次打開棧頂的Activity麼?

開發過程當中咱們常常會遇到各式各樣的bug,好比說測試小姐姐告訴咱們,因爲無操做,某個按鈕她快速點擊了兩次(或者因爲卡頓之類的延遲),打開了兩個詳情頁,但願把這個禁止掉,只讓打開一個詳情頁。java

快速點擊按鈕,屢次打開默認啓動模式的Activity

咱們先來複現下這種場景,Activity配置和按鈕點擊代碼很簡單,以下所示: activity配置:android

<activity
    android:name=".kfysts.chapter01.activity.LauncherModeSecondActivity"
    android:launchMode="standard" />
複製代碼

按鈕的點擊事件:git

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

咱們快速點擊三下按鈕,效果大概以下圖所示:程序員

咱們看下任務棧信息,在終端中輸入以下命令,將數據導入到log.txt中:github

不瞭解日誌重定向的同窗,請看重定向adb logcat輸出到文件.shell

adb shell dumpsys activity activities > log.txt
複製代碼

打開log.txt,咱們看下任務棧信息:bash

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打開了三次。app

使用singleTop進行防止屢次打開

小姐姐提的bug咱們不能無論,針對這個bug咱們第一反應是作一個防止View的屢次點擊,不過這裏咱們有更好的選擇。針對點擊打開Activity這種操做,可使用Activity啓動模式——singleTop來解決,這種啓動模式的核心就是,位於棧頂的Activity不會再次建立實例。post

singTop的解釋以下:測試

singleTop:棧頂複用模式。

在這種模式下,若是新Activity已經位於任務棧的棧頂,那麼此Activity不會被從新建立,同時它的onNewIntent方法會被調用,經過此方法的參數咱們能夠取出當前請求的信息。

若是新Activity的實例已存在但不是位於棧頂,那麼新Activity仍然會從新建立。
複製代碼

話很少說,咱們使用singleTop模式來優化下,在AndroidManifest.xml文件中,給對應的Activity添加android:launchMode="singleTop",代碼以下:

<activity
    android:name=".kfysts.chapter01.activity.LaunchModeSingleTopTestActivity"
    android:launchMode="singleTop" />
複製代碼

點擊啓動的代碼以下: 這裏新增了一條log,咱們能夠經過log來肯定具體點擊了幾回。

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

而後咱們嘗試屢次點擊按鈕,會發現屢次打開Activity的問題已經解決了。

先看下log,咱們確實屢次點擊了按鈕:

com.tiny.demo.firstlinecode E: single Top clicked
com.tiny.demo.firstlinecode E: single Top clicked
com.tiny.demo.firstlinecode E: single Top clicked
複製代碼

再看下效果圖,以下圖:

再來看下具體的任務棧信息,執行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}]
複製代碼

從結果中能夠看到,LaunchModeSingleTopTestActivity在棧頂確實只有一個實例。

綜合以上的結果,咱們能夠得出結論,singleTop啓動模式確實解決了棧頂Activity重複打開的問題,在屢次點擊的狀況下,棧頂Activity只打開了一次。

singleTop真的能徹底防止屢次打開棧頂的Activity麼?

雖然咱們的bug完美解決了,但做爲程序員,咱們仍是須要槓精下的。

這裏我改下點擊事件的代碼,瞬間屢次調用啓動activity的代碼,代碼以下:

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

而後咱們看下效果:

納尼,居然打開了多個。

再看下任務棧信息:

* 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確實打開了五次。

其實這也很好理解,無論任何操做都是須要時間去執行的,咱們的activity的啓動過程也是。

即便咱們給Activity設置了啓動模式,他們也不是馬上生效的,也須要執行到對應的代碼邏輯後纔會生效。

因此若是我在for循環裏面瞬間執行屢次打開Activity的操做,那麼啓動模式生效的代碼還未執行到,因此啓動模式就不會生效。

固然了,代碼中通常也不會這麼寫,知其然並知其因此然纔是咱們的目的。

github項目地址:Android_Base_Demo

具體頁面打開路徑:

具體頁面地址:github.com/tinyvampire…

參考

Android開發藝術探索

相關文章
相關標籤/搜索