最近公司測試測出來這么一個問題
具體表現(xiàn)是:
1,用QQ將我們自己的apk包從電腦端傳送到手機端,點擊安裝鸽扁,安裝成功后點擊QQ瀏覽器的打開按鈕(這時候的邏輯應該是觸發(fā)閃屏頁蒜绽,然后finish掉閃屏頁,接著跳轉到主頁Activity(主頁Activity是SignleTask設計模式的))
2桶现,然后點擊Home鍵躲雅,回到桌面
3,再在桌面上點擊app的icon巩那,原諒耿直的我們都是覺得應該直接回到【主頁Activity】吏夯,但是結果卻是又一次觸發(fā)?【閃屏頁Activity】,亮瞎了24K鈦合金狗眼的我們覺得這玩法不對吧即横?
4噪生,但是在QQ安裝器安裝成功后,不點擊QQ瀏覽器頁面的打開按鈕东囚,而是回到桌面點擊app的icon跺嗽,接著執(zhí)行2和3步驟,是不會有問題的
4页藻,好吧桨嫁,只能自己分析原因解決問題了
現(xiàn)象分析
上面兩種操作方式的不同點在于也就是啟動App的入口不一樣。一者是平常的桌面Icon圖標啟動份帐,一者是QQ安裝這類第三方平臺啟動璃吧,我們都知道,桌面啟動的話也是通過startActivity這個api通過特定的Intent向ActivityManageService發(fā)起啟動任務废境,所以可以推測出的是QQ安裝啟動這類方式也是通過Intent啟動對應的App畜挨,所以,可以肯定的是噩凹,通過QQ安裝啟動這類方式和通過桌面點擊app的icon圖標方式并不完全一致
背景知識
1巴元,Activity的Task管理
我們都知道,當一個具有singleTask啟動模式的Activity請求啟動后驮宴,比如Activity A逮刨,系統(tǒng)首先會尋找是否存在A想要的任務棧,如果不存在堵泽,則就重新創(chuàng)建一個任務棧修己,然后創(chuàng)建A的實例把A放到任務棧中,如果存在A所需的任務棧迎罗,這時候要看A在棧中是否有實例存在箩退,如果有實例存在,那么系統(tǒng)就會把A調到棧頂并調用它的onNewIntent,如果實例不存在佳谦,就創(chuàng)建A的實例并把A壓入棧中戴涝,那什么是A想要的任務棧呢,這就涉及到Activity的TaskAffinity,可以翻譯為任務相關性,這個參數(shù)標示了一個Activity所需要的任務棧的名字啥刻,默認情況下奸鸯,所有Activity所需的任務棧的名字為應用的包名。當然可帽,我們可以為每個Activity都單獨制定TaskAffinity娄涩,這個屬性值必須不能和包名相同,否則就相當于沒有指定映跟,需要指出的是TaskAffinity主要和singleTask啟動模式配對使用蓄拣,在其他情況下并沒有意義。
一般來說努隙,Android系統(tǒng)中App的啟動與切換依賴于Activity的Task管理球恤,下面簡單分析一下不同應用之間切換時候相關Task的變化,根據(jù)上面的分析荸镊,一個應用中可能有多個Task咽斧,一個Task中也有可能有多個Activity,為了簡單起見躬存,下面假設A张惹、B、C三個應用都是單Task的
桌面程序App(A):【TaskA】 ---- 存在Activity有【A1】 ---- ?其棧的結構為 A1
應用程序B:【TaskB】 ---- 存在Activity有【B1】【B2】 ---- 其棧的結構為 B1B2
應用程序C: 【TaskC】?----?存在Activity有【C1】【C2】 ----?其棧的結構為 C1C2
依次進行下面的操作
a岭洲、那么我們進入桌面時:Task之間的結構是 A1 ---- 也就是只有一個【TaskA】棧(桌面Task)宛逗,并且位于最前端(這里表現(xiàn)為最后添加的末端)
b、然后我們點擊應用程序B的圖標盾剩,啟動B :Task之間的結構是 A1B1B2? ---- 添加了一個【TaskB】雷激,而且【TaskB】也是位于最前端,現(xiàn)在顯示的是【TaskB】的B2的Activity的界面
c彪腔、接著點擊home鍵: Android對于home做了特殊默認處理侥锦,就是會把桌面Task挪到所以Task最前端进栽,Task結構應該變成??B1B2A1 ---- 【TaskA】挪到隊列最前端德挣,現(xiàn)在顯示的是【TaskA】的A1的Activity的界面,也就是桌面
d快毛、我們再在桌面點擊應用程序C的圖標格嗅,啟動C : Task之間的結構變成?B1B2A1C1C2 ----?添加了一個【TaskC】,而且【TaskC】也是位于最前端唠帝,現(xiàn)在顯示的是【TaskC】的C2的Activity的界面
好了屯掖,說了這么多,下面接著分析bug
原理剖析
從此我們可以知道QQ安裝器其實也就是使用Intent來啟動其剛剛安裝的那個App襟衰,但是問題所在的是:他們的啟動Intent并沒有跟桌面的啟動Intent完全一致贴铜!
而從柯元旦所著的《android內核剖析》一書中有記錄如下規(guī)則:
每次啟動Intent導致新創(chuàng)建Task的時候,該Task會記錄導致其創(chuàng)建的Intent;而如果后續(xù)需要有一個新的與創(chuàng)建Intent完全一致(完全一致定位為:啟動類绍坝,action徘意、category等等全部一樣,不可多項也不可缺少)轩褐,那么該Intent并不會觸發(fā)Activity的新建啟動椎咧,而只會將已經(jīng)存在的對應Task移到前臺;這也就是為什么桌面會在再次點擊圖標時將后臺任務挪到前臺而不是重新啟動App的實現(xiàn)把介。
我們將桌面的Task記為【TaskL】勤讽,QQ安裝器的Task記為【TaskQ】,我們應用的Task記為【TaskA】拗踢,那么分析如下:(L1是單純的桌面)
打開QQ:?L1Q1Q2 ---- Q2是安裝完畢后詢問是否啟動對應程序的Activity
點擊打開:?L1Q1Q2A2 ---- A1是入口閃屏頁脚牍,A2是主頁Activity,啟動后A1業(yè)務邏輯應該finish掉秒拔,所以從【TaskA】中挪去
返回桌面:?Q1Q2A2L1 ---- 回到桌面頁莫矗,也就是L1前置
點擊A的圖標:?Q1Q2L1A2A1 -> Q1Q2L1A2A1?---- 找到【TaskA】,挪到前臺砂缩,由于比對Intent并不是完全一致作谚,所以該請求是新啟動Activity,那么把A1添加到對應的【TaskA】中庵芭,然后A1所再一次觸發(fā)啟動主頁妹懒,但是主頁是singleTask模式,所以又回到了上次對應的A2主頁双吆,所以現(xiàn)象為再一次出現(xiàn)閃屏頁眨唬,然后回到原先的主頁界面。
解決思路
1好乐、讓騰訊那些第三方平臺修正其啟動Intent的設置匾竿,使其與原聲桌面啟動Intent保持完全一致。(PS:基本不可能)
2蔚万、自身業(yè)務代碼規(guī)避岭妖,我們可以知道,如果是多余的閃屏頁入口Activity的話反璃,其基本不可能位于Task的根部昵慌,而如果正常啟動的話,閃屏頁入口Activity必定在多對應的Task的根部位置淮蜈,那么我們可以從這個地方對于這個bug進行規(guī)避斋攀,方法就是在閃屏頁入口Activity的onCreate代碼加入如下一段代碼:
// 避免從桌面啟動程序后,會重新實例化入口類的activity
if(!this.isTaskRoot()) {
? ? Intent intent = getIntent();
? ? if(intent !=null) {
? ? ? ? String action = intent.getAction();
? ? ? ? if(intent.hasCategory(Intent.CATEGORY_LAUNCHER) && Intent.ACTION_MAIN.equals(action)) {
? ? ? ? ? ? finish();
? ? ? ? ? ? return;
? ? ? ? }
? ? }
}
?問題解決梧田!
https://www.cnblogs.com/net168/p/5722752.html