Android基礎(chǔ)總結(jié)篇之三:Activity的task相關(guān)介紹
本篇文章主要介紹了android基礎(chǔ)總結(jié)篇之三:Activity的task相關(guān),具有一定的參考價(jià)值,有需要的可以了解一下。
今天我們來(lái)講一下Activity的task相關(guān)內(nèi)容。
上次我們講到Activity的四種啟動(dòng)模式的時(shí)候,已經(jīng)了解到一些關(guān)于task的技術(shù),今天我再向大家介紹一下。task是一個(gè)具有棧結(jié)構(gòu)的容器,可以放置多個(gè)Activity實(shí)例。啟動(dòng)一個(gè)應(yīng)用,系統(tǒng)就會(huì)為之創(chuàng)建一個(gè)task,來(lái)放置根Activity;默認(rèn)情況下,一個(gè)Activity啟動(dòng)另一個(gè)Activity時(shí),兩個(gè)Activity是放置在同一個(gè)task中的,后者被壓入前者所在的task棧,當(dāng)用戶按下后退鍵,后者從task被彈出,前者又顯示在幕前,特別是啟動(dòng)其他應(yīng)用中的Activity時(shí),兩個(gè)Activity對(duì)用戶來(lái)說(shuō)就好像是屬于同一個(gè)應(yīng)用;
系統(tǒng)task和task之間是互相獨(dú)立的,當(dāng)我們運(yùn)行一個(gè)應(yīng)用時(shí),按下Home鍵回到主屏,啟動(dòng)另一個(gè)應(yīng)用,這個(gè)過(guò)程中,之前的task被轉(zhuǎn)移到后臺(tái),新的task被轉(zhuǎn)移到前臺(tái),其根Activity也會(huì)顯示到幕前,過(guò)了一會(huì)之后,在此按下Home鍵回到主屏,再選擇之前的應(yīng)用,之前的task會(huì)被轉(zhuǎn)移到前臺(tái),系統(tǒng)仍然保留著task內(nèi)的所有Activity實(shí)例,而那個(gè)新的task會(huì)被轉(zhuǎn)移到后臺(tái),如果這時(shí)用戶再做后退等動(dòng)作,就是針對(duì)該task內(nèi)部進(jìn)行操作了。
我們今天就講一下和task相關(guān)的知識(shí),主要分一下幾點(diǎn):
1.Activity的affinity(親和力)
2.Intent幾種常見(jiàn)的flags
3.<activity>與task相關(guān)屬性
affinity:
affinity對(duì)于Activity來(lái)說(shuō)就好像它的身份證一樣,可以告訴所在的task,自己屬于這個(gè)task中的一員;擁有相同affinity的多個(gè)Activity理論同屬于一個(gè)task,task自身的affinity決定于根Activity的affinity值。affinity在什么場(chǎng)合應(yīng)用呢?1.根據(jù)affinity重新為Activity選擇宿主task(與allowTaskReparenting屬性配合工作);2.啟動(dòng)一個(gè)Activity過(guò)程中Intent使用了FLAG_ACTIVITY_NEW_TASK標(biāo)記,根據(jù)affinity查找或創(chuàng)建一個(gè)新的具有對(duì)應(yīng)affinity的task。我們會(huì)在后面進(jìn)行詳細(xì)講解。
默認(rèn)情況下,一個(gè)應(yīng)用內(nèi)的所有Activity都具有相同的affinity,都是從Application(參考<application>的taskAffinity屬性)繼承而來(lái),而Application默認(rèn)的affinity是<manifest>中的包名,我們可以為<application>設(shè)置taskAffinity屬性值,這樣可以應(yīng)用到<application>下的所有<activity>,也可以單獨(dú)為某個(gè)Activity設(shè)置taskAffinity。例如:在系統(tǒng)自帶的Browser中,package為com.Android.browser,但是<application>卻自定義一個(gè)taskAffinity屬性值:
<application android:name="Browser" android:label="@string/application_name" android:icon="@drawable/ic_launcher_browser" android:backupAgent=".BrowserBackupAgent" android:taskAffinity="android.task.browser" >
Intent幾種常見(jiàn)的flags:
在android.content.Intent中定義了若干個(gè)flags,其中最重要的有以下幾個(gè):
1.FLAG_ACTIVITY_NEW_TASK:當(dāng)Intent對(duì)象包含這個(gè)標(biāo)記時(shí),系統(tǒng)會(huì)尋找或創(chuàng)建一個(gè)新的task來(lái)放置目標(biāo)Activity,尋找時(shí)依據(jù)目標(biāo)Activity的taskAffinity屬性進(jìn)行匹配,如果找到一個(gè)task的taskAffinity與之相同,就將目標(biāo)Activity壓入此task中,如果查找無(wú)果,則創(chuàng)建一個(gè)新的task,并將該task的taskAffinity設(shè)置為目標(biāo)Activity的taskActivity,將目標(biāo)Activity放置于此task。注意,如果同一個(gè)應(yīng)用中Activity的taskAffinity都使用默認(rèn)值或都設(shè)置相同值時(shí),應(yīng)用內(nèi)的Activity之間的跳轉(zhuǎn)使用這個(gè)標(biāo)記是沒(méi)有意義的,因?yàn)楫?dāng)前應(yīng)用task就是目標(biāo)Activity最好的宿主。下面我們會(huì)通過(guò)實(shí)例進(jìn)行演示這個(gè)特性:
我們新建兩個(gè)項(xiàng)目,分別命名為appA和appB,并且分別創(chuàng)建FirstActivity和SecondActivity,我們準(zhǔn)備讓appB中的FirstActivity跳轉(zhuǎn)到appA的SecondActivity。appA中的SecondActivity配置如下:
<activity android:name=".SecondActivity"> <intent-filter> <action android:name="android.intent.action.APP_A_SECOND_ACTIVITY" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity>
然后,在appB中的FirstActivity跳轉(zhuǎn)代碼如下:
Intent intent = new Intent("android.intent.action.APP_A_SECOND_ACTIVITY"); startActivity(intent);
我們要演示幾個(gè)步驟:1.在appB中的FirstActivity點(diǎn)擊按鈕跳轉(zhuǎn)到appA中的SecondActivity;2.按Home鍵回到主屏,在主選單中再次啟動(dòng)appB;3.按Home鍵回到主屏,在主選單中啟動(dòng)appA。演示過(guò)程如圖所示:
再次啟動(dòng)appB應(yīng)用:
啟動(dòng)appA應(yīng)用:
我們發(fā)現(xiàn)在從appB跳轉(zhuǎn)到appA的SecondActivity之后,SecondActivity實(shí)例好像是嵌入到了appB中,但是不影響appA的正常運(yùn)行,這種關(guān)系如下圖所示:
然后我們修改一下跳轉(zhuǎn)的代碼:
Intent intent = new Intent("android.intent.action.APP_A_SECOND_ACTIVITY"); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent);
我們加上了FLAG_NEW_TASK標(biāo)記,在來(lái)看一下演示結(jié)果:
再次啟動(dòng)appB:
啟動(dòng)appA:
我們看到差別了吧,當(dāng)我們?cè)俅螁?dòng)appB時(shí)已經(jīng)看不到剛才啟動(dòng)的appA中的SecondActivity,而啟動(dòng)appA時(shí)卻直接看到了,說(shuō)明這個(gè)SecondActivity實(shí)例并不在appB的task內(nèi),而是創(chuàng)建了一個(gè)task,這個(gè)task的affinity就是SecondActivity默認(rèn)的affinity,由于appA的SecondActivity的affinity是從Application繼承而來(lái),所以當(dāng)appA啟動(dòng)時(shí)會(huì)直接找到這個(gè)task,而不是創(chuàng)建新的task。我們看一下解析圖:
2.FLAG_ACTIVITY_CLEAR_TOP:當(dāng)Intent對(duì)象包含這個(gè)標(biāo)記時(shí),如果在棧中發(fā)現(xiàn)存在Activity實(shí)例,則清空這個(gè)實(shí)例之上的Activity,使其處于棧頂。例如:我們的FirstActivity跳轉(zhuǎn)到SecondActivity,SecondActivity跳轉(zhuǎn)到ThirdActivity,而ThirdActivity又跳到SecondActivity,那么ThirdActivity實(shí)例將被彈出棧,使SecondActivity處于棧頂,顯示到幕前,棧內(nèi)只剩下FirstActivity和SecondActivity。這個(gè)SecondActivity既可以在onNewIntent()中接收到傳來(lái)的Intent,也可以把自己銷毀之后重新啟動(dòng)來(lái)接受這個(gè)Intent。在使用默認(rèn)的“standard”啟動(dòng)模式下,如果沒(méi)有在Intent使用到FLAG_ACTIVITY_SINGLE_TOP標(biāo)記,那么它將關(guān)閉后重建,如果使用了這個(gè)FLAG_ACTIVITY_SINGLE_TOP標(biāo)記,則會(huì)使用已存在的實(shí)例;對(duì)于其他啟動(dòng)模式,無(wú)需再使用FLAG_ACTIVITY_SINGLE_TOP,它都將使用已存在的實(shí)例,Intent會(huì)被傳遞到這個(gè)實(shí)例的onNewIntent()中。
下面我們來(lái)驗(yàn)證一下這個(gè)過(guò)程:
首先,Activity啟動(dòng)模式都按照默認(rèn)值“standard”。從FirstActivity跳轉(zhuǎn)到SecondActivity,SecondActivity實(shí)例如下:
從ThirdActivity跳轉(zhuǎn)到SecondActivity時(shí),跳轉(zhuǎn)代碼如下:
Intent intent = new Intent(this, SecondActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); startActivity(intent);
然后跳轉(zhuǎn)后SecondActivity實(shí)例如下:
從序列號(hào)可以看到這兩個(gè)實(shí)例是不同的,證明它是經(jīng)過(guò)了銷毀和重新的過(guò)程。
然后我們把ThirdActivity中的跳轉(zhuǎn)代碼添加FLAG_ACTIVITY_SINGLE_TOP標(biāo)記:
Intent intent = new Intent(this, SecondActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP); startActivity(intent);
兩次實(shí)例均如下圖所示:
如果我們不想添加FLAG_ACTIVITY_SINGLE_TOP,那么把SecondActivity的啟動(dòng)模式改為“standard”之外的三種即可,效果和上面一樣,都不會(huì)創(chuàng)建新的實(shí)例。
3.FLAG_ACTIVITY_SINGLE_TOP:當(dāng)task中存在目標(biāo)Activity實(shí)例并且位于棧的頂端時(shí),不再創(chuàng)建一個(gè)新的,直接利用這個(gè)實(shí)例。我們?cè)谏线叺睦又幸灿兄v到。
4.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET:如果一個(gè)Intent中包含此屬性,則它轉(zhuǎn)向的那個(gè)Activity以及在那個(gè)Activity其上的所有Activity都會(huì)在task重置時(shí)被清除出task。當(dāng)我們將一個(gè)后臺(tái)的task重新回到前臺(tái)時(shí),系統(tǒng)會(huì)在特定情況下為這個(gè)動(dòng)作附帶一個(gè)FLAG_ACTIVITY_RESET_TASK_IF_NEEDED標(biāo)記,意味著必要時(shí)重置task,這時(shí)FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET就會(huì)生效。經(jīng)過(guò)測(cè)試發(fā)現(xiàn),對(duì)于一個(gè)處于后臺(tái)的應(yīng)用,如果在主選單點(diǎn)擊應(yīng)用,這個(gè)動(dòng)作中含有FLAG_ACTIVITY_RESET_TASK_IF_NEEDED標(biāo)記,長(zhǎng)按Home鍵,然后點(diǎn)擊最近記錄,這個(gè)動(dòng)作不含F(xiàn)LAG_ACTIVITY_RESET_TASK_IF_NEEDED標(biāo)記,所以前者會(huì)清除,后者不會(huì)。關(guān)于這個(gè)標(biāo)記,可以下圖示之:
這個(gè)標(biāo)記對(duì)于應(yīng)用存在分割點(diǎn)的情況會(huì)非常有用。比如我們?cè)趹?yīng)用主界面要選擇一個(gè)圖片,然后我們啟動(dòng)了圖片瀏覽界面,但是把這個(gè)應(yīng)用從后臺(tái)恢復(fù)到前臺(tái)時(shí),為了避免讓用戶感到困惑,我們希望用戶仍然看到主界面,而不是圖片瀏覽界面,這個(gè)時(shí)候我們就要在轉(zhuǎn)到圖片瀏覽界面時(shí)的Intent中加入此標(biāo)記。
5.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED:這個(gè)標(biāo)記在以下情況下會(huì)生效:1.啟動(dòng)Activity時(shí)創(chuàng)建新的task來(lái)放置Activity實(shí)例;2.已存在的task被放置于前臺(tái)。系統(tǒng)會(huì)根據(jù)affinity對(duì)指定的task進(jìn)行重置操作,task會(huì)壓入某些Activity實(shí)例或移除某些Activity實(shí)例。我們結(jié)合上面的CLEAR_WHEN_TASK_RESET可以加深理解。
<activity>的task相關(guān)屬性
在<activity>中定義了幾個(gè)常見(jiàn)的task相關(guān)屬性,它們分別代表了task內(nèi)部不同的行為特征,我們就來(lái)逐個(gè)介紹一下:
1.android:allowTaskReparenting
這個(gè)屬性用來(lái)標(biāo)記一個(gè)Activity實(shí)例在當(dāng)前應(yīng)用退居后臺(tái)后,是否能從啟動(dòng)它的那個(gè)task移動(dòng)到有共同affinity的task,“true”表示可以移動(dòng),“false”表示它必須呆在當(dāng)前應(yīng)用的task中,默認(rèn)值為false。如果一個(gè)這個(gè)Activity的<activity>元素沒(méi)有設(shè)定此屬性,設(shè)定在<application>上的此屬性會(huì)對(duì)此Activity起作用。例如在一個(gè)應(yīng)用中要查看一個(gè)web頁(yè)面,在啟動(dòng)系統(tǒng)瀏覽器Activity后,這個(gè)Activity實(shí)例和當(dāng)前應(yīng)用處于同一個(gè)task,當(dāng)我們的應(yīng)用退居后臺(tái)之后用戶再次從主選單中啟動(dòng)應(yīng)用,此時(shí)這個(gè)Activity實(shí)例將會(huì)重新宿主到Browser應(yīng)用的task內(nèi),在我們的應(yīng)用中將不會(huì)再看到這個(gè)Activity實(shí)例,而如果此時(shí)啟動(dòng)Browser應(yīng)用,就會(huì)發(fā)現(xiàn),第一個(gè)界面就是我們剛才打開(kāi)的web頁(yè)面,證明了這個(gè)Activity實(shí)例確實(shí)是宿主到了Browser應(yīng)用的task內(nèi)。我們就來(lái)結(jié)合實(shí)例演示一下這個(gè)過(guò)程:
首先,在appB的FirstActivity中,我們將跳轉(zhuǎn)動(dòng)作做以下改動(dòng):
Intent viewIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.google.com.hk")); startActivity(viewIntent);
進(jìn)入appB時(shí)的界面:
啟動(dòng)web界面之后:
然后我們按Home鍵,是當(dāng)前應(yīng)用退居后臺(tái),我們回到主選單,重新啟動(dòng)appB,界面如下:
此時(shí)我們?cè)谥鬟x單中啟動(dòng)Browser應(yīng)用,出現(xiàn)在我們眼前的界面是這樣的:
以上這種行為也證明了我們前面的論斷,為了更清楚的說(shuō)明問(wèn)題,也為了讓大家自己可以驗(yàn)證,下面我們要再次演示一下appB和appA的啟動(dòng)過(guò)程:
對(duì)于appA,在上面的基礎(chǔ)上,不用修改其他地方,只需為SecondActivity的<activity>元素添加一個(gè)屬性,如下:
<activity android:name=".SecondActivity" android:allowTaskReparenting="true"> ... </activity>
然后,在appB中的FirstActivity跳轉(zhuǎn)代碼改為:
Intent intent = new Intent("android.intent.action.APP_A_SECOND_ACTIVITY"); startActivity(intent);
我們啟動(dòng)appB,看到一下界面:
然后點(diǎn)擊按鈕,跳轉(zhuǎn)到appA中的SecondActivity,界面如下:
此時(shí)appB中的FirstActivity和appA中的SecondActivity處于同一個(gè)task中taskid為28,然后我們按下Home鍵,在主選單中再次啟動(dòng)appB,我們發(fā)現(xiàn)appA的SecondActivity不見(jiàn)了,我們看到的是:
然后我們啟動(dòng)appA,這是我們不會(huì)看到它的FirstActivity,而是看到了它的SecondActivity:
通常兩個(gè)應(yīng)用分別有自己的task,它們的taskid肯定不同,但這里的SecondActivity卻顯示taskid與appB相同,我們想一下也許就明白了,原來(lái)它是appB遷徙過(guò)來(lái)的,再啟動(dòng)appA時(shí)并未生成任何新的Activity實(shí)例。這個(gè)時(shí)候如果我們按下后退鍵,appA就會(huì)立即退出,證明了此時(shí)appA的task里只有一個(gè)Activity實(shí)例,也就是這個(gè)SecondActivity實(shí)例。
需要注意的是,如果appB退居后臺(tái)之后,沒(méi)有再次啟動(dòng)appB,而是直接啟動(dòng)appA,將不會(huì)出現(xiàn)以上現(xiàn)象。重新宿主的動(dòng)作發(fā)生在appB再次啟動(dòng)的過(guò)程中。
android:allowReparenting的效果圖如下:
2.android:alwaysRetainTaskState
這個(gè)屬性用來(lái)標(biāo)記應(yīng)用的task是否保持原來(lái)的狀態(tài),“true”表示總是保持,“false”表示不能夠保證,默認(rèn)為“false”。此屬性只對(duì)task的根Activity起作用,其他的Activity都會(huì)被忽略。
默認(rèn)情況下,如果一個(gè)應(yīng)用在后臺(tái)呆的太久例如30分鐘,用戶從主選單再次選擇該應(yīng)用時(shí),系統(tǒng)就會(huì)對(duì)該應(yīng)用的task進(jìn)行清理,除了根Activity,其他Activity都會(huì)被清除出棧,但是如果在根Activity中設(shè)置了此屬性之后,用戶再次啟動(dòng)應(yīng)用時(shí),仍然可以看到上一次操作的界面。
這個(gè)屬性對(duì)于一些應(yīng)用非常有用,例如Browser應(yīng)用程序,有很多狀態(tài),比如打開(kāi)很多的tab,用戶不想丟失這些狀態(tài),使用這個(gè)屬性就極為恰當(dāng)。
3.android:clearTaskOnLaunch
這個(gè)屬性用來(lái)標(biāo)記是否從task清除除根Activity之外的所有的Activity,“true”表示清除,“false”表示不清除,默認(rèn)為“false”。同樣,這個(gè)屬性也只對(duì)根Activity起作用,其他的Activity都會(huì)被忽略。
如果設(shè)置了這個(gè)屬性為“true”,每次用戶重新啟動(dòng)這個(gè)應(yīng)用時(shí),都只會(huì)看到根Activity,task中的其他Activity都會(huì)被清除出棧。如果我們的應(yīng)用中引用到了其他應(yīng)用的Activity,這些Activity設(shè)置了allowTaskReparenting屬性為“true”,則它們會(huì)被重新宿主到有共同affinity的task中。
無(wú)圖無(wú)真相,我們就來(lái)以實(shí)例演示一下這個(gè)過(guò)程,我們首先修改appB的根Activity的<activity>元素,如下:
<activity android:name=".FirstActivity" android:clearTaskOnLaunch="true"> ... </activity>
FristActivity界面如下:
然后我們讓FirstActivity跳轉(zhuǎn)到SecondActivity,結(jié)果如下:
然后我們按Home鍵回到主界面,再次啟動(dòng)appB,我們看到以下結(jié)果:
我們看到,再次啟動(dòng)appB時(shí),我們只能看到FirstActivity界面,此時(shí)在FirstActivity之上的所有Activity都已經(jīng)被清除出棧。示意圖如下:
4.android:finishOnTaskLaunch
這個(gè)屬性和android:allowReparenting屬性相似,不同之處在于allowReparenting屬性是重新宿主到有共同affinity的task中,而finishOnTaskLaunch屬性是銷毀實(shí)例。如果這個(gè)屬性和android:allowReparenting都設(shè)定為“true”,則這個(gè)屬性勝出。
以上就是今天總結(jié)的內(nèi)容,這些都是常用的知識(shí),除此之外還有很多等著我們?nèi)ヌ剿?,繼續(xù)努力。
原文鏈接:http://blog.csdn.net/liuhe688/article/details/6761337
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
使用Android實(shí)現(xiàn)一個(gè)懸浮在軟鍵盤(pán)上的輸入欄
app開(kāi)發(fā)中經(jīng)常會(huì)遇到一些輸入框要懸浮到軟鍵盤(pán)上方的需求,下面這篇文章主要給大家介紹了關(guān)于如何使用Android實(shí)現(xiàn)一個(gè)懸浮在軟鍵盤(pán)上的輸入欄的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-04-04Android中Fragment的基本用法示例總結(jié)
Fragment是activity的界面中的一部分或一種行為,下面這篇文章主要給大家介紹了關(guān)于Android中Fragment的基本用法的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下2018-05-05Android 通過(guò)代碼設(shè)置、打開(kāi)wifi熱點(diǎn)及熱點(diǎn)連接的實(shí)現(xiàn)代碼
這篇文章主要介紹了Android 通過(guò)代碼設(shè)置、打開(kāi)wifi熱點(diǎn)及熱點(diǎn)連接的實(shí)現(xiàn)代碼,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2018-05-05android獲取當(dāng)前運(yùn)行Activity名字的方法
這篇文章主要介紹了android獲取當(dāng)前運(yùn)行Activity名字的方法,對(duì)比分析了兩種實(shí)現(xiàn)方法供大家選擇,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-01-01Android自定義圓環(huán)倒計(jì)時(shí)控件
這篇文章主要為大家詳細(xì)介紹了Android自定義圓環(huán)倒計(jì)時(shí)控件,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-09-09Android Studio3.6新特性之視圖綁定ViewBinding使用指南
這篇文章主要介紹了Android Studio3.6新特性之視圖綁定ViewBinding使用指南,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-03-03Android入門(mén)之彈出式對(duì)話框的實(shí)現(xiàn)
Android Studio里有一種Dialog叫PopWindow,它是一種“可阻塞式Dialog”,即彈出后除非你給它一個(gè)“動(dòng)作”否則就一直顯示在那。本文就將實(shí)現(xiàn)這樣的彈出式對(duì)話框,感興趣的可以了解一下2022-11-11Android入門(mén)之Glide顯示網(wǎng)絡(luò)圖片高版本的使用詳解
這篇文章主要為大家詳細(xì)介紹了Android中Glide顯示網(wǎng)絡(luò)圖片高版本的使用方法,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起了解一下2023-02-02Android中判斷網(wǎng)絡(luò)是否連接實(shí)例詳解
這篇文章主要介紹了Android中判斷網(wǎng)絡(luò)是否連接實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下2017-01-01