開發過程當中咱們常常會遇到各式各樣的bug,好比說測試小姐姐告訴咱們,因爲無操做,某個按鈕她快速點擊了兩次
(或者因爲卡頓之類的延遲),打開了兩個詳情頁
,但願把這個禁止掉
,只讓打開一個詳情頁。java
咱們先來複現下這種場景,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
小姐姐提的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只打開了一次。
雖然咱們的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開發藝術探索