Activity的啓動模式及應用場景

Activity的啓動模式及應用場景

Activity的啓動模式如今說起來似乎是個古老的話題,可又不得不承認它是個很重要的內容,從android誕生到現在,這些啓動模式一直在發揮着作用,只不過不容易被人感覺到它們的存在。我們隨手敲下一行startActivity代碼就伴隨着一個啓動該activity的啓動模式。這些啓動模式將會影響到應用的返回行爲。從A啓動B,再按back鍵,會返回到A嗎?不一定。爲什麼呢?請往下看。

關於task

在介紹啓動模式之前有必要先介紹一下android中Task的概念,因爲它與activity息息相關。引用 官網 的話來說:

Task是用戶在執行某項工作時與之互動的一系列 Activity 的集合。這些 Activity 按照每個 Activity 打開的順序排列在一個返回堆棧中。

通俗地講,Task就是一個棧,裏面放了很多activity,當你按back鍵的時候系統會將當前task的棧頂activity出棧,然後在屏幕上顯示新的棧頂activity。看一下下面這個圖:

在這裏插入圖片描述

介紹完task,接下來具體說一說activity的4種啓動模式:

一、standard(標準模式,也是默認啓動模式)

standard是最常用的一種啓動模式,使用該模式啓動Activity,每次啓動一個Activity都會重寫創建一個新的實例,不管這個實例存不存在,這種模式下,誰啓動了該模式的Activity,該Activity就屬於啓動它的Activity的任務棧中。
但是,如果直接在Application中以標準模式啓動Activity,則會報出以下錯誤(Android7、Android8除外):

Calling startActivity() from outside of an Activity  context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?
at android.app.ContextImpl.startActivity(ContextImpl.java:912)
at android.app.ContextImpl.startActivity(ContextImpl.java:888)
at android.content.ContextWrapper.startActivity(ContextWrapper.java:379)

在這裏插入圖片描述

應用場景:

應用最廣,絕大多數app內的activity都是這種啓動方式,比如在首頁點一個菜單,進入具體的功能頁

二、signalTop(棧頂單一模式)

使用這個模式啓動activity,如果要啓動的activity已經位於棧頂,那麼這個Activity不會被重新創建,它的onCreate(),onStart()方法不會被調用,只有它的onNewIntent方法會被調用,通過此方法的參數我們可以去處理當前請求的信息。

如果棧頂不存在該Activity的實例,則情況與standard模式相同。會新建這個activity的實例,併入棧。

在這裏插入圖片描述

應用場景:

網易新聞。 假設主界面爲 MainActivity,顯示新聞的界面是 DetailActivity,顯然顯示任何一條新聞都會使用 DetailActivity,即把新聞內容通過 Intent 傳給 DetailActivity 就可以了。 假設你正在看新聞1(即在 DetailActivity),此時手機收到服務器的推送:收到一條通知(新聞2),點擊通知就會跳轉到 DetailActivity 並顯示新聞2,當你點擊通知時,因爲目前棧頂的 Activity 就是 DetailActivity,因此這裏就是使用 SingleTop 的地方,即點擊通知後以 SingleTop 加載模式打開 DetailActivity 並顯示新聞2,因此新聞1的 DetailActivity 就被覆蓋掉了。 此後你點擊返回鍵會回到主界面。

三、signalTask(棧內單一模式)

這個模式的行爲較複雜,它還可以與其它標誌位組合出多種行爲。

3.1 先說默認行爲,就是其它標誌位都不指定,採用默認值

此時啓動一個activity,如果棧中存在這個Activity的實例就會複用這個Activity,不管它是否位於棧頂,複用時,會將它上面的Activity全部出棧,並且會回調該實例的onNewIntent方法。如果棧中不存在這個Activity的實例就會新建一個實例併入棧。

3.2 同時指定taskAffinity的值

這裏又分爲兩種情況:

a、假設從appA啓動一個activity,啓動時指定的taskAffinity的值爲aapA的包名,那麼行爲跟3.1一樣,實際上如果不指定,默認值就是aapA的包名,因此它們的行爲是一致的。

b、假設從appA啓動一個activity,啓動時指定的taskAffinity的值不是aapA的包名,比如是taskB,那麼系統首先會去尋找當前是否存在一個叫“taskB”的任務棧,
如果不存在,則會創建一個新的Task,名字叫“taskB”。並創建新的Activity實例入棧到新創建的Task中去。
如果存在,則得到該任務棧,查找該任務棧中是否存在該Activity實例,如果存在實例,則將它上面的Activity實例都出棧,然後回調啓動的Activity實例的onNewIntent方法,如果不存在該實例,則新建Activity,併入棧。
此外,我們可以將兩個不同App中的Activity設置爲相同的taskAffinity,這樣雖然在不同的應用中,但是Activity會被分配到同一個Task中去。

以上幾種情況,目標task都會被調到前臺,這樣可以實現從appA中調起AppB。

在這裏插入圖片描述

應用場景:

從appA調起小程序,在小程序處理完事情之後返回app,此時小程序是通過調用我們app裏面的WXEntryActivity來喚起原本處於後臺的app的,而WXEntryActivity正是標記了singleTask,使得app可以從後臺回到前臺。

四、signalInstance

該模式具備singleTask模式的所有特性外,與它的區別就是,這種模式下的Activity會單獨佔用一個Task棧,具有全局唯一性,即整個系統中就這麼一個實例,由於棧內複用的特性,後續的請求均不會創建新的Activity實例,除非這個特殊的任務棧被銷燬了。以singleInstance模式啓動的Activity在整個系統中是單例的,如果在啓動這樣的Activiyt時,已經存在了一個實例,那麼會把它所在的任務調度到前臺,重用這個實例。

在這裏插入圖片描述

應用場景:

鬧鈴的響鈴界面。 你以前設置了一個鬧鈴:上午6點。在上午5點58分,你啓動了鬧鈴設置界面,並按 Home 鍵回桌面;在上午5點59分時,你在微信和朋友聊天; 在6點時,鬧鈴響了,並且彈出了一個對話框形式的 Activity(名爲 AlarmAlertActivity) 提示你到6點了(這個 Activity 就是以 SingleInstance 加載模式打開的),你按返回鍵,回到的是微信的聊天界面,這是因爲 AlarmAlertActivity 所在的 Task 的棧只有他一個元素, 因此退出之後這個 Task 的棧空了。如果是以 SingleTask 打開 AlarmAlertActivity,那麼當鬧鈴響了的時候,按返回鍵應該進入鬧鈴設置界面。

最後,再說一下taskAffinity與allowTaskReparenting結合使用的情況

allowTaskReparenting的主要作用是activity的遷移,即從一個task遷移到另一個task,這個遷移跟activity的taskAffinity有關。當allowTaskReparenting的值爲“true”時,則表示Activity能從啓動的Task移動到有着相同affinity的Task(當這個Task進入到前臺時),當allowTaskReparenting的值爲“false”,表示它必須呆在啓動時所在的那個Task裏。默認值爲“false”。

應用場景:

  1. 在某外賣 App 中下好訂單後,跳轉到支付寶進行支付。當在支付寶中支付成功之後,頁面停留在支付寶支付成功頁面。

  2. 按 Home 鍵,在主頁面重新打開支付寶,頁面上顯示的並不是支付寶主頁面,而是之前的支付成功頁面。

  3. 再次進入外賣 App,可以發現支付寶成功頁面已經消失。

在這裏插入圖片描述




由於水平有限,如果文中存在錯誤之處,請大家批評指正,歡迎大家一起來分享、探討!

博客:http://blog.csdn.net/MingHuang2017

GitHub:https://github.com/MingHuang1024

Email: [email protected]

itHub:https://github.com/MingHuang1024

Email: [email protected]

微信:724360018

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章