android 怎么自定义任务栈,Android中的Activity详解--启动模式与任务栈
目錄
Activity
生命周期
任務棧
啟動模式
Intent Flag
taskAffinity屬性
1.Activity
activity的簡單介紹就不寫了,作為最常用的四大組件之一,肯定都很熟悉其基本用法了。
2.生命周期
首先,是都很熟悉的一張圖,即官方介紹的Activity生命周期圖.
Activity生命周期圖
情景:打開某個應用的的FirstActivity調用方法如下:
由于之前已經很熟悉了,這里就簡單貼一些圖。
Paste_Image.png
按下返回鍵:
Paste_Image.png
重新打開并按下home鍵:
Paste_Image.png
再重新打開:
Paste_Image.png
在其中打開一個DialogActivity(SecondActivity)
Paste_Image.png
按下返回:
Paste_Image.png
修改SecondAcitvity為普通Activity,依舊是上述操作:
Paste_Image.png
這里強調一下onSaveInstanceState(Bundle outState)方法的調用時機:
當Activity有可能被系統殺掉時調用,注意,一定是被系統殺掉,自己調用finish是不行的。
測試如下:FirstActivity啟動SecondActivity:
Paste_Image.png
如果SecondActivity是android:theme="@android:style/Theme.Dialog"那么:
Paste_Image.png
如果FirstActivity啟動SecondActivity后自己調用了finish方法:
Paste_Image.png
也就是說,只要一個Activity轉為后臺,那么就會調用此方法,因為其有可能被系統殺掉,其中存的Bundle對象就是用來存儲數據的,這個也就是onCreate方法中Bundle對象參數savedInstanceState的由來。
3.Acitvity任務棧
一個App會包含很多個Activity,多個Activity之間通過intent進行跳轉,那么原始的Activity就是使用棧這個數據結構來保存的。
Task
A task is a collection of activities that users interact with when performing a certain job. The activities are arranged in a stack (theback stack), in the order in which each activity is opened.
即若干個Activity的集合的棧表示一個Task。
當App啟動時如果不存在當前App的任務棧就會自動創建一個,默認情況下一個App中的所有Activity都是放在一個Task中的,但是如果指定了特殊的啟動模式,那么就會出現同一個App的Activity出現在不同的任務棧中的情況,即會有任務棧中包含來自于不同App的Activity。
4.啟動模式
standard
標準模式,在不指定啟動模式的情況下都是以此種方式啟動的。每次啟動都會創建一個新的Activity實例,覆蓋在原有的Activity上,原有的Activity入棧。
測試如下:在FirstActivity中啟動FirstActivity:
Paste_Image.png
當只有一個FirstActivity時堆棧情況:
Paste_Image.png
當在FirstActivity中啟動FirstActivity時堆棧情況:
Paste_Image.png
這就很顯然了,任務棧中一共有兩個FirstActivity,即表示每次啟動FirstActivity都是創建了一個新的實例。
singleTop
此種模式下,Activity在啟動時會進行判斷,如果當前的App的棧頂的Activity即正在活動的Activity就是將要啟動的Activity,那么就不會創建新的實例,直接使用棧頂的實例。
測試,設置FirstActivity為此啟動模式,多次點擊FirstActivity中的啟動FirstActivity的按鈕查看堆棧情況:
(其實點擊按鈕沒有啟動新Activity的動畫就可以看出并沒有啟動新Activity)
Paste_Image.png
果然,堆棧中只有一個FirstActivity
如果我在FirstActivity中啟動了SecondActivity,此時FirstActivity不就不在棧頂了么,此時我再啟動FirstActivity會怎樣呢?
測試如下:
Paste_Image.png
很好的驗證了,只有在棧頂時,才不會創建新實例。
這種啟動模式很適用于接收到消息之后進行顯示的界面,總不能每次來消息都創建新實例,那一次來個十幾條消息豈不是爆炸了。
在此種模式下,在不創建新的實例的時候,會調用onNewIntent()方法。
總結:棧頂的Activity只會有一個實例,在棧頂的情況下重復啟動該Activity只會復用該Activity,而不會創建一個新的,除了棧頂的Activity外,其他的和standard類似,每次啟動都會被創建一個新的實例。
onNewIntent(Intent intent)方法介紹
官方解釋如下:
This is called for activities that set launchMode to "singleTop" in
* their package, or if a client used the {@link Intent#FLAG_ACTIVITY_SINGLE_TOP}
* flag when calling {@link #startActivity}. In either case, when the
* activity is re-launched while at the top of the activity stack instead
* of a new instance of the activity being started, onNewIntent() will be
* called on the existing instance with the Intent that was used to
* re-launch it.
*
*
An activity will always be paused before receiving a new intent, so
* you can count on {@link #onResume} being called after this method.
*
*
Note that {@link #getIntent} still returns the original Intent. You
* can use {@link #setIntent} to update it to this new Intent.
*
* @param intent The new intent that was started for the activity.
大意就是:
對于使用singleTop啟動或Intent.FLAG_ACTIVITY_SINGLE_TOP啟動的Activity,當該Activity被重復啟動(注意一定是re-launched,第一次啟動時不會調用)時就會調用此方法。
且調用此方法之前會先暫停Activity也就是先調用onPause方法。
而且,即使是在新的調用產生后此方法被調用,但是通過getIntent方法獲取到的依舊是以前的Intent,可以通過setIntent方法設置新的Intent。
方法參數就是新傳遞的Intent.
singleTask
1.如果是同一個App中啟動某個設置了此模式的Activity的話,如果棧中已經存在該Activity的實例,那么就會將該Activity上面的Activity清空,并將此實例放在棧頂。
測試:SecondActivity啟動模式設為singleTask,啟動三個Activity:
Paste_Image.png
然后在ThirdActivity中啟動SecondActivity(注意不是返回,而是啟動):
Paste_Image.png
果然,SecondActivity上的ThirdActivity被清掉了
2.如果是其他應用的Activity啟動的本應用中此Activity,那么
- 本應用未啟動時,在另一個應用的ActivityY中啟動SecondActivity:
Paste_Image.png
顯然,此時這個SecondActivity是在一個單獨的任務棧中的,且是處于前臺的,按下返回鍵,SecondActivity結束,返回到ActivityY。
- 本應用已經啟動了,在后臺運行,任務棧中是FirstActivity和SecondActivity,在另一個應用的ActivityY中啟動此Activity,此時任務棧的狀態:
Paste_Image.png
兩個任務棧,每個棧中都有兩個Activity。
注意,此時如果按下返回鍵,會出現什么情況呢,到底是返回到ActivityY,還是返回到FirstActivity?
結果如下:
Paste_Image.png
前臺Activity竟然變成了FirstActivity!繼續按下返回鍵,就會返回到ActivityY,ActivityX,然后退出。
也就是說,在ActivityY啟動了SecondActivity時,連帶著SecondActivity的任務棧也被帶到了前臺。
那么我不禁要問了,如果SecondActivity啟動模式是默認的,會不會是此種情況呢?,其實按照我們前面學的,按照分析的話,應該是SecondActivity在ActivityY所在的App所對應的任務棧中創建一個新的實例,跟原本的SecondActivity所在后臺任務棧沒有一毛錢關系。
- 本應用已經啟動了三個Activity,任務棧中是FirstActivity和SecondActivity和ThirdActivity,此時再由ActivityY啟動:
那么稍微思考一下就可以肯定運行結果跟上面是完全相同的,因為在跳轉到SecondActivity時,其上面的Activity已經被清空了。
singleInstance
這個模式就很好記,以此模式啟動的Activity會存放在一個單獨的任務棧中,且只會有一個實例。
測試:SecondActivity啟動模式設為singleInstance
FirstActivity->SesondActivity->ThirdActivity->SecondActivity->ThirdActivity
結果:
Paste_Image.png
顯然,啟動了兩次ThirdActivity任務棧中就有兩個實例,而SecondActivity在另外一個任務棧中,且只有一個。
5.Intent Flag設置啟動模式
在使用Intent啟動一個Activity時可以設置啟動該Activity的啟動模式:
這個屬性有很多,大致列出幾個:
Intent.FLAG_ACTIVITY_NEW_TASK
每個啟動的Activity都在一個新的任務棧中
Intent.FLAG_ACTIVITY_SINGLE_TOP
singleTop
Intent.FLAG_ACTIVITY_CLEAR_TOP
singleTask
Intent.FLAG_ACTIVITY_NO_HISTORY
用此種方式啟動的Activity,在它啟動了其他Activity后,會自動finish.
6.taskAffinity屬性
官方文檔介紹如下:
The task that the activity has an affinity for. Activities with the same affinity conceptually belong to the same task (to the same "application" from the user's perspective). The affinity of a task is determined by the affinity of its root activity.The affinity determines two things — the task that the activity is re-parented to and the task that will house the activity when it is launched with the FLAG_ACTIVITY_NEW_TASK flag.
By default, all activities in an application have the same affinity. You can set this attribute to group them differently, and even place activities defined in different applications within the same task. To specify that the activity does not have an affinity for any task, set it to an empty string.
If this attribute is not set, the activity inherits the affinity set for the application (see theelement's taskAffinity.
The name of the default affinity for an application is the package name set by theelement.
大意如下:
這個屬性表示的是一個Activity對任務棧的親和度。有相同的affinity的Activity屬于同一個Task,即affinity相同的Activity會被加入同一任務棧。一個任務棧的affinity由其affinity值確定或是其根Activity的affinity確定。這個屬性決定兩件事,①Activity被re-parented時的任務棧,②以FLAG_ACTIVITY_NEW_TASK啟動的Activity所在的任務棧。
默認情況下,同一個應用內的所有的Activity都擁有相同的affinity,你可以通過設置這個值來給Activity分組,甚至將不同應用的Activity放在相同的任務棧中。為了表明一個Activity對任何一個任務棧都不具有親和力,那么將其設為空字符串。
如果這個值沒有設置,那么就默認使用application標簽下的這個值。
默認的affinity值為manifest標簽下設置的包名。
這樣看來的話,通俗易懂的講,就是給每一個任務棧起個名,給每個Activity也起個名,在Activity以singleTask模式啟動時,就檢查有沒有跟此Activity的名相同的任務棧,有的話就將其加入其中。沒有的話就按照這個Activity的名創建一個任務棧。
測試:在App1中設置SecondActivity的taskAffinity為“gsq.test”,App2中的ActivityX的taskAffinity也設為“gsq.test”
FirstActivity->SesondActivity->home->ActivityX
任務棧信息如下:
Paste_Image.png
結果很顯然了。
測試:在上述基礎上,在ActivityX中進行跳轉到ActivityY,ActivityY不指定啟動模式和taskAffinity。結果如下:
Paste_Image.png
發現ActivityY在gsq.test任務棧中,這是由于其啟動模式是Standard,也就是在啟動這個Activity的所在的任務任務棧中。
再將ActivityY指定啟動模式singleTask:
Paste_Image.png
這樣就沒問題了,ActivityY在一個新的任務棧中,名稱為包名。
這時從ActivityY跳轉到SecondActivity,那應該是gsq.test任務棧只有SecondActivity,ActivityX已經沒有了。因為其啟動模式是singleTask,在啟動它時發現已經有一個實例存在,就把它所在的任務棧上面的Activity都清空了并將其置于棧頂。
還有一點需要提一下,在上面,FirstActivity是App1的lunch Activity,但是由于SecondActivity并沒有指定MAIN和LAUNCHER過濾器,故在FirstActivity跳轉到SecondActivity時,按下home鍵,再點開App1,回到的是FirstActivity。
大致就先寫這么多吧,好像有點長,廢話有點多,估計也有錯別字,不要太在意~~~
總結
以上是生活随笔為你收集整理的android 怎么自定义任务栈,Android中的Activity详解--启动模式与任务栈的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Shiro的authc过滤器的执行流程
- 下一篇: 西南科技大学OJ题 单链表中信息的分