Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Activity四種啟動模式

Activity四種啟動模式

編輯:關於Android編程

網上有很多相關文章的介紹,這裡就不多說了。只是通過案例來解釋內容,因為有些內容理解起來還是比較費勁的,如果理解錯了,那就得糾結好一陣子了。

standard

略過

singleTop

目前我了解兩種情況,下面分別描述。
第一種:
當前任務棧:A-B-C-D
操作:D為singleTop,從D中再次啟動D
此時的任務棧:A-B-C-D
D的生命周期為:onNewIntent() - onResume()。
結論:D沒有重新創建,而是走了onNewIntent()和onResume()方法,需要注意不會走onStart()方法。

第二種:
當前的任務棧:A-B-C-D
操作:C為singleTop,從D中再次啟動C
此時的任務棧:A-B-C-D-C
C的生命周期為:onCreate()-onStart()-onResume()。

結論:C重新創建了,這種情況C會出現多個實例。

使用Flag:
對應的Flag為Intent.FLAG_ACTIVITY_SINGLE_TOP
以上面第一種為例,刪除D中的singleTop,還是在D中啟動D:

        Intent intent = new Intent(this, D1.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
        startActivity(intent);

我在這裡犯了一個錯誤,不是在C1啟動D1的時候設置的flag,而是在D1啟動D1的時候設置flag。

singleTask

這個模式需要測試的情況比較多,下面分多個場景測試。

場景一:
當前的任務棧:A-B-C-D
操作:C為singleTask,從D中再次啟動C
此時的任務棧:A-B-C
C的生命周期為:onNewIntent()-onStart-onResume。

結論:1:C沒有重新創建,而是生命周期發生如上變化,這裡我留意到比singleTop多走了onStart方法。
2:C上面的Activity D出棧了,這裡C上面只有D,其實不管C上面有多少個Activity,都會出棧。

這裡測試還沒完,很多文章寫的singleTask會創建一個新棧,我們看下是否真的創建了新棧。
日志如下:
07-19 15:22:58.276 20391-20391/com.lxq.app1 D/TaskId: 95—–A1
07-19 15:22:59.532 20391-20391/com.lxq.app1 D/TaskId: 95—–B1
07-19 15:23:00.390 20391-20391/com.lxq.app1 D/TaskId: 95—–C1
07-19 15:23:01.739 20391-20391/com.lxq.app1 D/TaskId: 95—–D1
07-19 15:23:04.082 20391-20391/com.lxq.app1 D/TaskId: 95—–C1

顯然沒有創建一個新棧,其實創建新棧指的是啟動另外一個APP的時候會創建新棧,而不是在當前APP操作。於是繼續測試。

准備工作:
App1中的Activity - A1,B1,C1,D1
App2中的Activity - A2,B2,C2,D2

操作:
App1中的A1啟動App2中的B2,把B2的啟動模式改為singleTask。

日志:
07-19 15:42:51.940 22780-22780/com.lxq.app1 D/TaskId: 106—–A1
07-19 15:42:56.189 22434-22434/com.lxq.app2 D/TaskId: 107—–B2

結論:同一個APP中,Activity設置singleTask並不會創建新的任務棧,App1啟動App2中的設置有singleTask的Activity才會創建新的任務棧。那如果我非要在一個App中給不同Activity設置不同的棧,比如我要在App1中給A1,B1指定一個棧,給C1,D1指定一個棧,這個怎麼解決。很多文章和書籍都有介紹如何實現,使用affinity。

在測試affinity之前,我想拿剛才介紹的例子做幾個測試:
目前的情況:App1中的A1啟動了App2中的B2,他們來自兩個不同的任務棧,App1初始啟動Activity為A1,App2初始啟動Activity是A2。

第一個測試:
確保App2所有Activity完全關閉(專業點說就是沒有後台任務棧哈),啟動App1,在A1中啟動App2的B2,
然後Home鍵進入桌面,點擊App2的啟動圖標,正常情況下App2應該啟動A2。

結論:點擊App2後啟動是B2,按返回鍵後回到桌面。因為App2的棧內之前不存在B2,所以這裡B2的生命周期很明顯是從onCreate開始的,那麼問題來了,如果App2中,當前任務棧為A2-B2,然後按Home鍵回到桌面,再從App1中啟動App2中的B2,此時的B2生命周期又是怎樣的呢?繼續測試。

第二個測試:
確保App2中的任務棧為A2-B2,然後Home鍵,在App1中的A1去啟動App2中的B2,觀察此時B2的生命周期。

日志:
07-19 16:45:21.438 3673-3673/com.lxq.app2 D/ActivityLife: A2 - onCreate
07-19 16:45:21.442 3673-3673/com.lxq.app2 D/ActivityLife: A2 - onStart
07-19 16:45:21.442 3673-3673/com.lxq.app2 D/ActivityLife: A2 - onResume
07-19 16:45:28.581 3673-3673/com.lxq.app2 D/ActivityLife: B2 - onCreate
07-19 16:45:28.598 3673-3673/com.lxq.app2 D/ActivityLife: B2 - onStart
07-19 16:45:28.599 3673-3673/com.lxq.app2 D/ActivityLife: B2 - onResume
07-19 16:45:39.561 3673-3673/com.lxq.app2 D/ActivityLife: B2 - onNewIntent
07-19 16:45:39.584 3673-3673/com.lxq.app2 D/ActivityLife: B2 - onStart
07-19 16:45:39.585 3673-3673/com.lxq.app2 D/ActivityLife: B2 - onResume

結論:生命周期 onNewIntent-onStart-onResume。這個很好理解,App2中任務棧為A2,B2,B2為singleTask所以B2在棧內是唯一的,當App1啟動B2的時候不會創建新的實例,而是走onNewIntent()方法。其實這裡還有一種場景,這個測試場景是App2中任務棧為A2-B2,那如果App2中的任務棧為A2-B2-C2-D2呢,其實我也不知道,我猜如果App1中的A1啟動App2中的B2後,App2中的任務棧可能是A2-B2,B2的生命周期和上面相同onNewIntent-onStart-onResume。那就再麻煩一次了。

第三個測試:
確保App2中的任務棧為A2-B2-C2-D2,然後Home鍵,在App1中的A1去啟動App2中的B2,觀察此時B2的生命周期和APP2中的任務棧。

日志:
07-19 16:58:57.698 3673-3673/com.lxq.app2 D/ActivityLife: A2 - onCreate
07-19 16:58:57.703 3673-3673/com.lxq.app2 D/ActivityLife: A2 - onStart
07-19 16:58:57.703 3673-3673/com.lxq.app2 D/ActivityLife: A2 - onResume
07-19 16:58:59.439 3673-3673/com.lxq.app2 D/ActivityLife: B2 - onCreate
07-19 16:58:59.470 3673-3673/com.lxq.app2 D/ActivityLife: B2 - onStart
07-19 16:58:59.470 3673-3673/com.lxq.app2 D/ActivityLife: B2 - onResume
07-19 16:59:01.201 3673-3673/com.lxq.app2 D/ActivityLife: C2 - onCreate
07-19 16:59:01.205 3673-3673/com.lxq.app2 D/ActivityLife: C2 - onStart
07-19 16:59:01.205 3673-3673/com.lxq.app2 D/ActivityLife: C2 - onResume
07-19 16:59:02.595 3673-3673/com.lxq.app2 D/ActivityLife: D2 - onCreate
07-19 16:59:02.602 3673-3673/com.lxq.app2 D/ActivityLife: D2 - onStart
07-19 16:59:02.602 3673-3673/com.lxq.app2 D/ActivityLife: D2 - onResume
07-19 16:59:09.970 3673-3673/com.lxq.app2 D/ActivityLife: B2 - onNewIntent
07-19 16:59:10.004 3673-3673/com.lxq.app2 D/ActivityLife: B2 - onStart
07-19 16:59:10.004 3673-3673/com.lxq.app2 D/ActivityLife: B2 - onResume

結論:此時的任務棧為A2-B2,B2的生命周期onNewIntent-onStart-onResume。上面我猜對了。

如果把上面三個測試歸為一類,那麼還是以上三個測試中的第一個測試,再做一個測試,回顧一下該測試的條件:App1中的A1啟動App2中的B2,並且設置B2為singleTask,得到的結論是B2創建了一個新棧,那麼問題又來了,如果B2不設置singleTask,這個時候B2是否在A1的棧內?

日志:
07-19 17:10:53.635 2907-2907/com.lxq.app1 D/TaskId: 134—–A1
07-19 17:10:57.182 25342-25342/com.lxq.app2 D/TaskId: 134—–B2

結論:B2在A1所在的棧內,通過B2進入C2,D2,都會在A1所在的棧內。剛才上面做了三個測試,這裡就不做測試了,我測過了,直接下結論,如果是這種場景,不管APP2的棧內如何變化都與APP1沒有關系,APP1每次啟動APP2中B2都會創建一個新的實例,你點擊APP2的啟動圖標,也不會顯示B2,而是重新創建任務棧,顯示A2。我是這樣理解的,如果App2中的B2設置了singleTask,當App1中的A1啟動App2中的B2的時候,會給App2創建一個新棧,然後把B2壓入這個棧,當點擊App2啟動圖標的時候,會去查找App2中是否有任務棧存在,如果有則激活最頂層的Activity,這樣也就不難解釋點擊App2啟動圖標的時候,看到的不是A2,而是B2了。如果App2中的B2不設置singleTask,App1啟動B2的時候都會放在啟動B2的A1的棧內。

使用flag:
singleTask對應Intent.FLAG_ACTIVITY_NEW_TASK,據我測試,使用上他們並非完全等同。這裡我分別作了兩個測試:

第一個測試
在App1中,A1-B1-C1-D1,然後從D1再次啟動B1,並設置
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)

結論:最後的任務棧為A1-B1-C1-D1-B1,B1重建了,它們都在同一個任務棧。並沒有在amanifest中設置singleTask的效果,不走onNewIntent()方法,也不會移除B1上面的的任務棧(不會移除C1,D1)。有人會說需要使用taskAffinity,我測過,使用taskAffinity只是會給B1分配一個新的任務棧,最後任務棧還是沒變A1-B1-C1-D1-B1,只不過A1在一個任務棧,B1-C1-D1-B1在另外一個任務棧,還是不會走onNewIntent()方法,所以,總結為,在一個APP中,通過設置Intent.FLAG_ACTIVITY_NEW_TASK達不到singleTask的效果,當然我只是根據測試得出的結論,如果不對,歡迎糾正!

第二個測試
在App1中的A1去啟動App2中的B2,並設置
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
這種方式和設置singleTask有很多不同,這裡不細說了,自己可以測試一下。

現在解決上面提到的問題,在App1中給A1,B1指定一個棧,給C1,D1指定一個棧,這個怎麼解決?使用affinity。

TaskAffinity

TaskAffinity屬性主要和singleTask或allowTaskReparenting結合使用,其他情況沒有意義。

TaskAffinity和singleTask結合使用

只需要給C1如下設置:

        

07-20 04:57:22.851 10029-10029/com.lxq.app1 D/TaskId: 212—–A1
07-20 04:57:24.119 10029-10029/com.lxq.app1 D/TaskId: 212—–B1
07-20 04:57:25.161 10029-10029/com.lxq.app1 D/TaskId: 213—–C1
07-20 04:57:26.558 10029-10029/com.lxq.app1 D/TaskId: 213—–D1

TaskAffinity和allowTaskReparenting結合使用
現在使用App1中的A1啟動App2中的B2,並且,B2設置為:

        
            
                
                
            
        

可以發現這裡沒有設置TaskAffinity,如果不設置TaskAffinity默認為包名。這裡只是設置了一行代碼而已:android:allowTaskReparenting=”true”。

現在做如下操作:
1.清空所有任務棧,啟動App1,在A1中啟動App2中的B2。
日志如下:

07-20 05:22:48.170 30685-30685/com.lxq.app1 D/ActivityLife: A1 - onCreate
07-20 05:22:48.172 30685-30685/com.lxq.app1 D/ActivityLife: A1 - onStart
07-20 05:22:48.173 30685-30685/com.lxq.app1 D/ActivityLife: A1 - onResume—-240—–A1
07-20 05:22:52.310 30377-30377/com.lxq.app2 D/ActivityLife: B2 - onCreate
07-20 05:22:52.319 30377-30377/com.lxq.app2 D/ActivityLife: B2 - onStart
07-20 05:22:52.322 30377-30377/com.lxq.app2 D/ActivityLife: B2 - onResume—-240—–B2

現在App1中的任務棧情況 A1-B2,而且他們在一個任務棧,屬於A1的任務棧。
可以發現這時候A1和B2都在一個Task裡面,id為240。

2.Home鍵返回桌面,點擊App2的啟動圖標。

07-20 05:24:06.675 30377-30377/com.lxq.app2 D/ActivityLife: B2 - onStart
07-20 05:24:06.676 30377-30377/com.lxq.app2 D/ActivityLife: B2 - onResume—-239—–B2

顯示的是B2二不是A2,而且B2沒有走onCreate()方法,說明沒有重建,而且任務棧Id變成了239。感覺是B2從App1中轉移到了它App2的任務棧中,因為任務棧Id也變了。如果是轉移,那麼此時我回到桌面,再次點擊App1,那麼B2還在不在App1中呢,答案是不在。可以自己測試一下。如果測試到這一步,一定還會發現一個有趣的現象,現在B2轉移到App2的棧中了,也就是App2的棧中只有B2,按返回鍵應該返回到桌面,但是實際上不是這樣的,

日志如下:
07-20 05:29:44.606 4643-4643/com.lxq.app2 D/ActivityLife: B2 - onStart
07-20 05:29:44.608 4643-4643/com.lxq.app2 D/ActivityLife: B2 - onResume—-242—–B2
07-20 05:29:50.035 4643-4643/com.lxq.app2 D/ActivityLife: A2 - onCreate
07-20 05:29:50.039 4643-4643/com.lxq.app2 D/ActivityLife: A2 - onStart
07-20 05:29:50.039 4643-4643/com.lxq.app2 D/ActivityLife: A2 - onResume

並沒有回到桌面,而是去創建A2了,很奇怪。

另外還有一個問題,在App1中,如果A1,B1,在一個棧,C1,D1在一個棧,上面有寫,通過TaskAffinity可以實現。現在的棧內情況是 A1-B1-C1-D1,使用D1調用B1,棧內情況會變成C1-D1-A1-B1,如果D1調用A1,棧內情況為C1-D1-A1,B1會出棧。

下面提供測試項目,可以在這個基礎上完成上面的測試。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved