TaskAffinity應(yīng)用場(chǎng)景【轉(zhuǎn)】

轉(zhuǎn)載請(qǐng)注明出處(謝謝):
http://blog.csdn.net/javazejian/article/details/52072131

通過上一篇文件的分析,我們對(duì)Activity的啟動(dòng)模式有了比較清晰的了解后降淮,本篇我們將繼續(xù)對(duì)Activity啟動(dòng)模式的相關(guān)參數(shù)和任務(wù)棧分析佳鳖,接下來我們就繼續(xù)上一篇的問題系吩,如何通過taskAffinity屬性在同一個(gè)應(yīng)用中創(chuàng)建多個(gè)任務(wù)棧進(jìn)行探究穿挨。

任務(wù)棧之taskAffinity屬性

TaskAffinity特點(diǎn)如下:

  • TaskAffinity 參數(shù)標(biāo)識(shí)著Activity所需要的任務(wù)棧的名稱尊搬,默認(rèn)情況下土涝,一個(gè)應(yīng)用中所有Activity所需要的任務(wù)棧名稱都為該應(yīng)用的包名但壮。
  • TaskAffinity 屬性一般跟singleTask模式或者跟allowTaskReparenting屬性結(jié)合使用,在其他情況下沒有實(shí)際意義胳施。
  • TaskAffinity屬性的值不能與當(dāng)前應(yīng)用包名相同舞肆,否則其值跟作廢沒兩樣筷登。

TaskAffinity和singleTask啟動(dòng)模式結(jié)合使用

當(dāng)TaskAffinity和singleTask啟動(dòng)模式結(jié)合使用時(shí)前方,當(dāng)前Activity的任務(wù)棧名稱將與TaskAffinity屬性指定的值相同惠险,下面我們通過代碼來驗(yàn)證,我們同過MainActivity來啟動(dòng)ActivityA班巩,其中MainActivity啟動(dòng)模式為默認(rèn)模式趣竣,ActivityA啟動(dòng)模式為singleTask遥缕,而TaskAffinity屬性值為android:taskAffinity="com.zejian.singleTask.affinity" MainActivity和ActivityA代碼如下:


package comzejian.myapplication;
 
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
 
public class MainActivity extends AppCompatActivity {
 
    private Button btn;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        btn= (Button) findViewById(R.id.btn);
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent i = new Intent(MainActivity.this,ActivityA.class);
                startActivity(i);
            }
        });
    }
}

ActivityA.class 代碼如下:


package comzejian.myapplication;
 
import android.app.Activity;
import android.os.Bundle;
 
/**
 * Created by zejian
 * Time 16/7/26.
 * Description:
 */
public class ActivityA extends Activity{
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_a);
    }
}

清單文件代碼如下:


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="comzejian.myapplication">
 
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
 
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
 
        <activity android:name=".ActivityA"
                    android:launchMode="singleTask"
                    android:taskAffinity="com.zejian.singleTask.affinity"
            />
 
    </application>
</manifest>

現(xiàn)在我們啟動(dòng)MainActivity,后再啟動(dòng)ActivityA户秤,然后我們通過 adb shell dumpsys activity activities 命令查看此時(shí)棧的情況:

image

我們可以清楚地看到兩個(gè)任務(wù)棧转砖,其中一個(gè)是id=249鲸伴,棧名稱為com.zejian.singleTask.affinity的任務(wù)棧姓赤,該棧包含了ActivityA不铆,另外一個(gè)則是id=248裹唆,棧名為默認(rèn)包名的任務(wù)棧品腹,包含了MainActivity泡垃。到此我們也明白了羡鸥,我們確實(shí)可以通過singleTask與android:taskAffinity屬性相結(jié)合的方式來指定我們Activity所需要的棧名稱惧浴,使相應(yīng)的Activity存在于不同的棧中衷旅,圖解如下:


image

當(dāng)TaskAffinity和allowTaskReparenting結(jié)合使用

首先我們來聊聊allowTaskReparenting屬性茄袖,它的主要作用是activity的遷移宪祥,即從一個(gè)task遷移到另一個(gè)task,這個(gè)遷移跟activity的taskAffinity有關(guān)藏澳。當(dāng)allowTaskReparenting的值為“true”時(shí)翔悠,則表示Activity能從啟動(dòng)的Task移動(dòng)到有著affinity的Task(當(dāng)這個(gè)Task進(jìn)入到前臺(tái)時(shí))凉驻,當(dāng)allowTaskReparenting的值為“false”,表示它必須呆在啟動(dòng)時(shí)呆在的那個(gè)Task里效诅。如果這個(gè)特性沒有被設(shè)定乱投,元素(當(dāng)然也可以作用在每次activity元素上)上的allowTaskReparenting屬性的值會(huì)應(yīng)用到Activity上戚炫。默認(rèn)值為“false”双肤。這樣說可能還比較難理解茅糜,我們舉個(gè)例子素挽,比如現(xiàn)在有兩個(gè)應(yīng)用A和B预明,A啟動(dòng)了B的一個(gè)ActivityC撰糠,然后按Home鍵回到桌面物喷,再單擊B應(yīng)用時(shí),如果此時(shí)扇丛,allowTaskReparenting的值為“true”帆精,那么這個(gè)時(shí)候并不會(huì)啟動(dòng)B的主Activity卓练,而是直接顯示已被應(yīng)用A啟動(dòng)的ActivityC襟企,我們也可以認(rèn)為ActivityC從A的任務(wù)棧轉(zhuǎn)移到了B的任務(wù)棧中顽悼。這就好比我們?cè)诼愤吺震B(yǎng)了一只與主人走失了的貓,養(yǎng)著養(yǎng)著突然有一天木羹,主人找上門來了坑填,這只貓也就被帶回去了穷遂。我們通過圖解來更好地理解這種情景:

image

我們通過代碼層面來驗(yàn)證一下蚪黑,我們創(chuàng)建兩個(gè)應(yīng)用分別為ActivityTask(簡(jiǎn)稱A應(yīng)用)和ActivityTask2(簡(jiǎn)稱B應(yīng)用),其中A包含ActivityA掠剑,B包含ActivityC,我們通過ActivityA啟動(dòng)B應(yīng)用中的ActivityC朴译,再回到桌面躬翁,啟動(dòng)B應(yīng)用,此時(shí)我們觀察A應(yīng)用和B應(yīng)用各自棧的變化(因?yàn)锳,B為不同的應(yīng)用所以taskAfinity屬性值肯定不同盒发,所以這里我們就沒必要指定了)。
ActivityA及其清單文件代碼如下:

import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
 
/**
 * Created by zejian
 * Time 16/7/23.
 * Description:
 */
public class ActivityA extends Activity {
 
    private Button btnC;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_a);
 
        btnC= (Button) findViewById(R.id.mainC);
        btnC.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(Intent.ACTION_MAIN);
                intent.addCategory(Intent.CATEGORY_LAUNCHER);
                ComponentName cn = new ComponentName("com.cmcm.activitytask2", "com.cmcm.activitytask2.ActivityC");
                intent.setComponent(cn);
                startActivity(intent);
            }
        });
    }
}

<activity android:name=".ActivityA">
     <intent-filter>
           <action android:name="android.intent.action.MAIN" />
           <category android:name="android.intent.category.LAUNCHER" />
     </intent-filter>
</activity>

ActivityA及其清單文件代碼如下:


package com.cmcm.activitytask;
 
package com.cmcm.activitytask;
 
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
 
/**
 * Created by zejian
 * Time 16/7/23.
 * Description:
 */
public class ActivityC extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_c);
    }
}

<activity android:name=".ActivityC" android:exported="true"    
      android:allowTaskReparenting="true">
</activity>

我們通過AcitivityA啟動(dòng)B應(yīng)用的ActivityC后,內(nèi)存中棧的如下:


image

我們可以看到ActivityA和ActivityC同在一個(gè)棧中,接著我們回到桌面啟動(dòng)B應(yīng)用,此時(shí)內(nèi)存中的任務(wù)棧如下:


image

我們發(fā)現(xiàn)ActivityC從A應(yīng)用的任務(wù)棧直接移動(dòng)到B應(yīng)用的任務(wù)棧,這也就符合我們前面所說的現(xiàn)象了善涨。而當(dāng)我們修改allowTaskReparenting為false時(shí)窒盐,再運(yùn)行,然后重復(fù)上面的操作钢拧,查看內(nèi)存中任務(wù)棧的變化:
A應(yīng)用啟動(dòng)B應(yīng)用的ActivityC時(shí)


image

回到桌面再啟動(dòng)B應(yīng)用時(shí)


image

對(duì)比發(fā)現(xiàn)蟹漓,如果allowTaskReparenting值為false時(shí),ActivityC并不會(huì)直接從A應(yīng)用的任務(wù)棧遷移到B應(yīng)用的任務(wù)棧源内,而是B應(yīng)用直接重新創(chuàng)建了ActivityC的實(shí)例葡粒。到此我們對(duì)于allowTaskReparenting和taskAffinity屬性的了解就已經(jīng)相當(dāng)深入了,不過有點(diǎn)需要說明的是allowTaskReparenting僅限于singleTop和standard模式膜钓,這是因?yàn)橐粋€(gè)activity的affinity屬性由它的taskAffinity屬性定義(代表?xiàng)C┧越唬粋€(gè)task的affinity由它的root activity定義。所以,一個(gè)task的root activity總是擁有和它所在task相同的affinity梅肤。由于以singleTask和singleInstance啟動(dòng)的activity只能是一個(gè)task的root activity撩扒,因此allowTaskReparenting僅限于以standard 和singleTop啟動(dòng)的activity泉手,大家可以自行測(cè)試一下,這里我們就不測(cè)試了哈,下面我們?cè)賮碚f說它們可能應(yīng)用用場(chǎng)景。

TaskAffinity與allowTaskReparenting和singleTask結(jié)合時(shí)可能發(fā)生的應(yīng)用場(chǎng)景

  • TaskAffinity與singleTask應(yīng)用場(chǎng)景

假如現(xiàn)在有這么一個(gè)需求,我們的客戶端app正處于后臺(tái)運(yùn)行锰瘸,此時(shí)我們因?yàn)槟承┬枰∏屛⑿耪{(diào)用自己客戶端app的某個(gè)頁(yè)面茸俭,用戶完成相關(guān)操作后,我們不做任何處理,按下回退或者當(dāng)前Activity.finish(),頁(yè)面都會(huì)停留在自己的客戶端(此時(shí)我們的app回退棧不為空),這顯然不符合邏輯的,用戶體驗(yàn)也是相當(dāng)出問題的。我們要求是,回退必須回到微信客戶端,而且要保證不殺死自己的app.這時(shí)候我們的處理方案就是逻卖,設(shè)置當(dāng)前被調(diào)起Activity的屬性為:

LaunchMode=""SingleTask" taskAffinity="com.tencent.mm"

其中com.tencent.mm是借助于工具找到的微信包名盗迟,就是把自己的Activity放到微信默認(rèn)的Task棧里面黔衡,這樣回退時(shí)就會(huì)遵循“Task只要有Activity一定從本Task剩余Activity回退”的原則,不會(huì)回到自己的客戶端;而且也不會(huì)影響自己客戶端本來的Activity和Task邏輯听盖。

  • TaskAffinity與allowTaskReparenting應(yīng)用場(chǎng)景

一個(gè)e-mail應(yīng)用消息包含一個(gè)網(wǎng)頁(yè)鏈接腰吟,點(diǎn)擊這個(gè)鏈接將出發(fā)一個(gè)activity來顯示這個(gè)頁(yè)面,雖然這個(gè)activity是瀏覽器應(yīng)用定義的震捣,但是activity由于e-mail應(yīng)用程序加載的壹若,所以在這個(gè)時(shí)候該activity也屬于e-mail這個(gè)task语御。如果e-mail應(yīng)用切換到后臺(tái)骨田,瀏覽器在下次打開時(shí)由于allowTaskReparenting值為true,此時(shí)瀏覽器就會(huì)顯示該activity而不顯示瀏覽器主界面,同時(shí)actvity也將從e-mail的任務(wù)棧遷移到瀏覽器的任務(wù)棧,下次打開e-買了時(shí)并不會(huì)再顯示該activity
??到此TaskAffinity就全部介紹完了片橡,最后我們?cè)賮砹私鈳讉€(gè)跟任務(wù)棧相關(guān)的屬性參數(shù)舆吮;

清空任務(wù)棧

Android系統(tǒng)除了給我提供了TaskAffinity來指定任務(wù)棧名稱外,還給我提供了清空任務(wù)棧的方法,在一般情況下我們只需要在<activity>標(biāo)簽中指明相應(yīng)的屬性值即可挫鸽。

  • android:clearTaskOnLaunch

這個(gè)屬性用來標(biāo)記是否從task清除除根Activity之外的所有的Activity,“true”表示清除上遥,“false”表示不清除,默認(rèn)為“false”携狭。這里有點(diǎn)我們必須要注意的搁廓,這個(gè)屬性只對(duì)任務(wù)棧內(nèi)的root Activity起作用境蜕,任務(wù)棧內(nèi)其他的Activity都會(huì)被忽略拉庶。如果android:clearTaskOnLaunch屬性為“true”慷蠕,每次我們重新進(jìn)入這個(gè)應(yīng)用時(shí),我們只會(huì)看到根Activity盅视,任務(wù)棧中的其他Activity都會(huì)被清除出棧捐名。
??比如一個(gè)應(yīng)用的Activity A,B,C,其中clearTaskOnLaunch設(shè)置為true闹击,C為默認(rèn)值镶蹋,我們依次啟動(dòng)A,B,C,點(diǎn)擊HOME,再在桌面點(diǎn)擊圖標(biāo)赏半。啟動(dòng)的是A贺归,而B,C將都被移除當(dāng)前任務(wù)棧断箫。也就是說拂酣,當(dāng)Activity的屬性clearTaskOnLaunch為true時(shí)將被優(yōu)先啟動(dòng),其余的Activity(B仲义、C)都被移除任務(wù)棧并銷毀婶熬,除非前面A已經(jīng)finish銷毀锣光,后面的已注冊(cè)clearTaskOnLaunch為true的activity(B)才會(huì)生效。
??特別地痰哨,如果我們的應(yīng)用中引用到了其他應(yīng)用的Activity蚌铜,這些Activity設(shè)置了android:allowTaskReparenting屬性為“true”,則它們會(huì)被重新宿主到有共同affinity的task中饺谬。

  • android:finishOnTaskLaunch

finishOnTaskLaunch屬性與clearTaskOnLaunch 有些類似捂刺,它們的區(qū)別是finishOnTaskLaunch是作用在自己身上(把自己移除任務(wù)棧,不影響別的Activity)募寨,而clearTaskOnLaunch則是作用在別人身上(把別的Activity移除任務(wù)棧)族展,如果我們把Activity的android:finishOnTaskLaunch屬性值設(shè)置為true時(shí),離開這個(gè)Activity所依賴的任務(wù)棧后拔鹰,當(dāng)我們重新返回時(shí)仪缸,該Activity將會(huì)被finish掉,而且其他Activity不會(huì)受到影響格郁。

  • android:alwaysRetainTaskState

alwaysRetainTaskState實(shí)際上是給了當(dāng)前Activity所在的任務(wù)棧一個(gè)“免死金牌”腹殿,如果當(dāng)前Activity的android:alwaysRetainTaskState設(shè)置為true時(shí),那么該Activity所在的任務(wù)棧將不會(huì)受到任何清理命令的影響例书,一直保持當(dāng)前任務(wù)棧的狀態(tài)锣尉。

好了,到此本篇也就完結(jié)决采,相信通過兩篇的記錄我們對(duì)Activity的啟動(dòng)模式和任務(wù)棧都有相對(duì)清晰的了解了哈自沧。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市树瞭,隨后出現(xiàn)的幾起案子拇厢,更是在濱河造成了極大的恐慌,老刑警劉巖晒喷,帶你破解...
    沈念sama閱讀 217,185評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件孝偎,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡凉敲,警方通過查閱死者的電腦和手機(jī)衣盾,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來爷抓,“玉大人势决,你說我怎么就攤上這事±镀玻” “怎么了果复?”我有些...
    開封第一講書人閱讀 163,524評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)渤昌。 經(jīng)常有香客問我虽抄,道長(zhǎng)走搁,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,339評(píng)論 1 293
  • 正文 為了忘掉前任迈窟,我火速辦了婚禮朱盐,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘菠隆。我一直安慰自己,他們只是感情好狂秘,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,387評(píng)論 6 391
  • 文/花漫 我一把揭開白布骇径。 她就那樣靜靜地躺著,像睡著了一般者春。 火紅的嫁衣襯著肌膚如雪破衔。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,287評(píng)論 1 301
  • 那天钱烟,我揣著相機(jī)與錄音晰筛,去河邊找鬼。 笑死拴袭,一個(gè)胖子當(dāng)著我的面吹牛读第,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播拥刻,決...
    沈念sama閱讀 40,130評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼怜瞒,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了般哼?” 一聲冷哼從身側(cè)響起吴汪,我...
    開封第一講書人閱讀 38,985評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蒸眠,沒想到半個(gè)月后漾橙,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,420評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡楞卡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,617評(píng)論 3 334
  • 正文 我和宋清朗相戀三年霜运,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片臀晃。...
    茶點(diǎn)故事閱讀 39,779評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡觉渴,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出徽惋,到底是詐尸還是另有隱情案淋,我是刑警寧澤,帶...
    沈念sama閱讀 35,477評(píng)論 5 345
  • 正文 年R本政府宣布险绘,位于F島的核電站踢京,受9級(jí)特大地震影響誉碴,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜瓣距,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,088評(píng)論 3 328
  • 文/蒙蒙 一黔帕、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蹈丸,春花似錦成黄、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至荸百,卻和暖如春闻伶,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背够话。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工蓝翰, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人女嘲。 一個(gè)月前我還...
    沈念sama閱讀 47,876評(píng)論 2 370
  • 正文 我出身青樓畜份,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親澡为。 傳聞我的和親對(duì)象是個(gè)殘疾皇子漂坏,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,700評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容