本文出自 “阿敏其人” 簡書博客漱牵,轉(zhuǎn)載或引用請注明出處。
Android-Activity所應(yīng)該了解的大概就這樣疚漆。(上)
Android-Activity所應(yīng)該了解的大概就這樣酣胀。(中)
六、FLAG
我們知道愿卸,Android給Activity設(shè)定啟動模式的方式有有兩種灵临。一種是在?manifest里面設(shè)置,另一種是在通過Intent的FLAG設(shè)置趴荸。
FLAG儒溉,在安卓里面是 標(biāo)記位 的意思,F(xiàn)lag有很多種发钝,下面我們記錄主要使用的幾種顿涣。
代碼指定Flag(?使用全部FLAG),使得Activity啟動模式可變酝豪,而且最后一次指定的Flag就是該Activity在任務(wù)棧中最終啟動模式涛碑。
-
Intent.FLAG_ACTIVITY_NEW_TASK
??注:Intent.FLAG_ACTIVITY_NEW_TASK單獨(dú)使用并無任何效果,需要和taskAffinity一起配合著使用孵淘。- 當(dāng)和taskAffinity一起配合著使用時(shí):**Intent.FLAG_ACTIVITY_NEW_TASK + android:taskAffinity 指定非程序包名的任務(wù)棧名蒲障,?與清單文件里面指定 android:launchMode="singleInstance"效果一致 真心一致 ** (情況2示例)
- 這個(gè)Flag常用于在服務(wù)中啟動Activity,因?yàn)榉?wù)沒有Activity的任務(wù)棧,所以只能用一個(gè)新的任務(wù)棧來啟動這個(gè)Activity創(chuàng)建實(shí)例揉阎。
Intent.FLAG_ACTIVITY_SINGLE_TOP
??與清單文件里面指定 android:launchMode="singleTop"效果一致庄撮。真心一致。
??可嘗試作用采用FLAG_ACTIVITY_CLEAR_TOP退出整個(gè)程序(多activity)
- Intent.FLAG_ACTIVITY_CLEAR_TOP
Intent.FLAG_ACTIVITY_CLEAR_TOP與清單文件里面指定 android:launchMode="singleTask"效果類似毙籽,只是類似洞斯。因?yàn)楫?dāng)位于任務(wù)棧頂部的時(shí)候和android:launchMode="singleTask"產(chǎn)生很大的差別
設(shè)置次標(biāo)記位的Activity,當(dāng)它啟動的時(shí)候坑赡,同一個(gè)任務(wù)棧里面位于他上方的Activity會全部出棧烙如,上方全部清掉。
在一個(gè)打開時(shí)已經(jīng)被標(biāo)記為FLAG_ACTIVITY_CLEAR_TOP的界面(現(xiàn)正處于前臺任務(wù)棧的棧頂)毅否,如果我們在此界面打開自己亚铁,并且一樣標(biāo)記為FLAG_ACTIVITY_CLEAR_TOP,那么這個(gè)時(shí)候會經(jīng)歷一次建新毀舊的過程螟加,任務(wù)棧里面從結(jié)果的來說沒什么變化刀闷,但是生命周期的著眼于過程的角度來卻經(jīng)歷非常大的變化。(下面的情況5有示例)
mark下仰迁,這個(gè)標(biāo)記位通常是和FLAG_ACTIVITY_NEW_TASK配合著使用的。在這種情況下被啟動的Activty如果已經(jīng)存在顽分,那么系統(tǒng)就會調(diào)用它的onNewIntent方法徐许。如果被調(diào)用的Activity使用默認(rèn)的standrad模式,那么它連同它之上的Activity都要出棧卒蘸,系統(tǒng)會創(chuàng)建新的實(shí)例并入棧置為棧頂雌隅。還未嘗試
- Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
具有這個(gè)標(biāo)記的Activity不會出現(xiàn)在Activity的歷史列表中.
他等同于在xml里面設(shè)定 android:excludeFromRecents="true" 。
情景實(shí)測:
準(zhǔn)備工作
我們弄一個(gè)程序缸沃,一共有4個(gè)界面恰起,分別是
FirstActivity,這個(gè)作為啟動頁趾牧,接下的描述我們用A代替
SecondActivity 頁面2检盼,接下的描述我們用B代替
ThirdActivity 頁面3 ,接下的描述我們用C代替
FourthActivity 頁面4翘单, 接下的描述我們用D代替
界面布局類似吨枉,每一個(gè)頁面都有TextView寫清楚當(dāng)前是哪一個(gè)界面,并且每一個(gè)界面都會有三個(gè)Button哄芜,都是可以用于啟動頁面2貌亭,頁面3和頁面4.
就是上面那個(gè)樣子。
準(zhǔn)備工作至此完成
情景1:我們把所有按鈕的打開的Activity都設(shè)置為Intent.FLAG_ACTIVITY_NEW_TASK认臊,只有默認(rèn)的啟動頁是Standard圃庭。
完整過程是:然后啟動app,打開B,在B打開C剧腻,在C打開D拘央,然后在D打開B。
這個(gè)過程我們分兩步進(jìn)行恕酸。
結(jié)論先上:單獨(dú)給Activity的Intent設(shè)置Intent.FLAG_ACTIVITY_NEW_TASK沒有作用堪滨。
如果說Intent.FLAG_ACTIVITY_NEW_TASK直接等同于在xml將來啟動模式設(shè)置為singleTask的話,那么在我們 “在D打開B” 個(gè)操作中蕊温,應(yīng)該此時(shí)任務(wù)棧就應(yīng)該會清掉B以上的C和D袱箱,然后只剩下BA,但是結(jié)果是任務(wù)棧變成了BDCBA义矛,B只是相當(dāng)于一個(gè)普通的實(shí)例入棧发笔。所以這個(gè)說法不成立。
注:網(wǎng)上有人直接說Intent.FLAG_ACTIVITY_NEW_TASK就相當(dāng)于singleTask凉翻,這是錯(cuò)誤的了讨。
貼一下代碼,其實(shí)要是這么設(shè)置Flag特別傻逼制轰,不用這么每個(gè)都設(shè)置的前计,這里為了演示需要,大概怎么設(shè)置后面會提到的
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.amqr.flagtest" >
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme" >
<activity android:name=".FirstActivity" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".SecondActivity"/>
<activity android:name=".ThirdActivity"/>
<activity android:name=".FourthActivity"/>
</application>
</manifest>
接下來是四份代碼:
FirstActivity
public class FirstActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_first);
findViewById(R.id.mBtOpen2).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent openSecond = new Intent(FirstActivity.this, SecondActivity.class);
openSecond.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(openSecond);
}
});
findViewById(R.id.mBtOpen3).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent openThird = new Intent(FirstActivity.this, ThirdActivity.class);
openThird.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(openThird);
}
});
findViewById(R.id.mBtOpen4).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent openFourth = new Intent(FirstActivity.this, FourthActivity.class);
openFourth.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(openFourth);
}
});
}
}
.
.
SecondActivity
public class SecondActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
findViewById(R.id.mBtOpen2).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent openSecond = new Intent(SecondActivity.this, SecondActivity.class);
openSecond.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(openSecond);
}
});
findViewById(R.id.mBtOpen3).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent openThird = new Intent(SecondActivity.this,ThirdActivity.class);
openThird.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(openThird);
}
});
findViewById(R.id.mBtOpen4).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent openFourth = new Intent(SecondActivity.this,FourthActivity.class);
openFourth.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(openFourth);
}
});
}
}
.
.
FourthActivity
public class FourthActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fourth);
findViewById(R.id.mBtOpen2).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent openSecond = new Intent(FourthActivity.this, SecondActivity.class);
openSecond.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(openSecond);
}
});
findViewById(R.id.mBtOpen3).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent openThird = new Intent(FourthActivity.this, ThirdActivity.class);
openThird.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(openThird);
}
});
findViewById(R.id.mBtOpen4).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent openFourth = new Intent(FourthActivity.this, FourthActivity.class);
openFourth.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(openFourth);
}
});
}
}
分兩個(gè)步驟垃杖,
第一步:
啟動app后A就啟動男杈,A打開B,B打開C调俘,C打開D
這是我們來看一下終端的信息:
Running activities (most recent first):
TaskRecord{52a650dc #6 A=com.amqr.flagtest U=0 sz=4}
Run #3: ActivityRecord{529b46e4 u0 com.amqr.flagtest/.FourthActivity t6}
Run #2: ActivityRecord{52983354 u0 com.amqr.flagtest/.ThirdActivity t6}
Run #1: ActivityRecord{5295f8c8 u0 com.amqr.flagtest/.SecondActivity t6}
Run #0: ActivityRecord{52958028 u0 com.amqr.flagtest/.FirstActivity t6}
這是任務(wù)棧里面有4個(gè)Activity伶棒,然后里面分別是DCBA,D為棧頂彩库。
第二步:
我們在D界面打開B
然后重新看一下終端的信息:
Running activities (most recent first):
TaskRecord{52a650dc #6 A=com.amqr.flagtest U=0 sz=5}
Run #4: ActivityRecord{52a3efe8 u0 com.amqr.flagtest/.SecondActivity t6}
Run #3: ActivityRecord{529b46e4 u0 com.amqr.flagtest/.FourthActivity t6}
Run #2: ActivityRecord{52983354 u0 com.amqr.flagtest/.ThirdActivity t6}
Run #1: ActivityRecord{5295f8c8 u0 com.amqr.flagtest/.SecondActivity t6}
Run #0: ActivityRecord{52958028 u0 com.amqr.flagtest/.FirstActivity t6}
我們發(fā)現(xiàn)肤无,這是在D界面打開的這個(gè)B并沒有把復(fù)用位于A上方的B并且把自己上方的CD清掉,而是像一個(gè)普通的任務(wù)棧入棧了骇钦。
現(xiàn)在任務(wù)棧里面有五個(gè)Activity宛渐,分別是BDCBA,棧頂是第二次打開的B眯搭。
證明結(jié)論:單獨(dú)給Activity的Intent設(shè)置Intent.FLAG_ACTIVITY_NEW_TASK沒有作用皇忿。
.
.
情景2
我們給A打開的B設(shè)置為Intent.FLAG_ACTIVITY_NEW_TASK,給B打開的C設(shè)置為Intent.FLAG_ACTIVITY_NEW_TASK坦仍,給C里面要打開的B和C設(shè)定為Intent.FLAG_ACTIVITY_NEW_TASK鳍烁。
然后重點(diǎn)在這里,在清單文件里面給B和C都屬性taskAffinity屬性繁扎。
我們給B設(shè)置了 android:taskAffinity="com.amqr.second222"
給C設(shè)置了 android:taskAffinity="com.amqr.third333"
結(jié)論先上:**Intent.FLAG_ACTIVITY_NEW_TASK + android:taskAffinity 指定非程序包名的任務(wù)棧名幔荒,?與清單文件里面指定 android:launchMode="singleInstance"效果一致 **
完整操作:A打開B糊闽,B打開C,C再打開C(這里是打不開的)爹梁,C打開B
附上代碼:
manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.amqr.flagtest" >
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme" >
<activity android:name=".FirstActivity" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".SecondActivity"
android:taskAffinity="com.amqr.second222"
/>
<activity android:name=".ThirdActivity"
android:taskAffinity="com.amqr.third333"
/>
<activity android:name=".FourthActivity"/>
</application>
</manifest>
接下來是代碼
FirstActivity
public class FirstActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_first);
findViewById(R.id.mBtOpen2).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent openSecond = new Intent(FirstActivity.this, SecondActivity.class);
openSecond.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(openSecond);
}
});
findViewById(R.id.mBtOpen3).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent openThird = new Intent(FirstActivity.this, ThirdActivity.class);
startActivity(openThird);
}
});
findViewById(R.id.mBtOpen4).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent openFourth = new Intent(FirstActivity.this, FourthActivity.class);
startActivity(openFourth);
}
});
}
}
.
.
SecondActivity
public class SecondActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
findViewById(R.id.mBtOpen2).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent openSecond = new Intent(SecondActivity.this, SecondActivity.class);
startActivity(openSecond);
}
});
findViewById(R.id.mBtOpen3).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent openThird = new Intent(SecondActivity.this, ThirdActivity.class);
openThird.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(openThird);
}
});
findViewById(R.id.mBtOpen4).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent openFourth = new Intent(SecondActivity.this, FourthActivity.class);
startActivity(openFourth);
}
});
}
}
.
.
ThirdActivity
public class ThirdActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_third);
findViewById(R.id.mBtOpen2).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent openSecond = new Intent(ThirdActivity.this, SecondActivity.class);
openSecond.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(openSecond);
}
});
findViewById(R.id.mBtOpen3).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent openThird = new Intent(ThirdActivity.this, ThirdActivity.class);
openThird.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(openThird);
}
});
findViewById(R.id.mBtOpen4).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent openFourth = new Intent(ThirdActivity.this, FourthActivity.class);
startActivity(openFourth);
}
});
}
}
操作分4步:
提醒:這里B和C被打開時(shí)都被指定 Intent.FLAG_ACTIVITY_NEW_TASK右犹,而且各自都指定了 android:taskAffinity 名稱為非程序包名的自定義任務(wù)棧名稱
步驟1:A打開B,
Running activities (most recent first):
TaskRecord{52a6e690 #54 A=com.amqr.second222 U=0 sz=1}
Run #1: ActivityRecord{529b601c u0 com.amqr.flagtest/.SecondActivity t54}
TaskRecord{52928e18 #53 A=com.amqr.flagtest U=0 sz=1}
Run #0: ActivityRecord{5297ded0 u0 com.amqr.flagtest/.FirstActivity t53}
我們發(fā)現(xiàn)此時(shí)程序里面有2個(gè)任務(wù)棧姚垃,一個(gè)是程序自帶的名字為包名的任務(wù)棧amqr.flagtest念链,一個(gè)是我們自定義名字的任務(wù)棧com.amqr.second222。
步驟2:B打開C
Running activities (most recent first):
TaskRecord{52b6a93c #55 A=com.amqr.third333 U=0 sz=1}
Run #2: ActivityRecord{52a8d5f8 u0 com.amqr.flagtest/.ThirdActivity t55}
TaskRecord{52a6e690 #54 A=com.amqr.second222 U=0 sz=1}
Run #1: ActivityRecord{529b601c u0 com.amqr.flagtest/.SecondActivity t54}
TaskRecord{52928e18 #53 A=com.amqr.flagtest U=0 sz=1}
Run #0: ActivityRecord{5297ded0 u0 com.amqr.flagtest/.FirstActivity t53}
此時(shí)有三個(gè)任務(wù)棧积糯,其中自定義名字的任務(wù)棧com.amqr.third333是前臺任務(wù)棧掂墓,其他兩個(gè)都是后臺任務(wù)棧。
步驟3:C打開C
我們發(fā)現(xiàn)看成,C沒有辦法打開C君编。所以任務(wù)棧里面沒有什么變化
TaskRecord{52b6a93c #55 A=com.amqr.third333 U=0 sz=1}
Run #2: ActivityRecord{52a8d5f8 u0 com.amqr.flagtest/.ThirdActivity t55}
TaskRecord{52a6e690 #54 A=com.amqr.second222 U=0 sz=1}
Run #1: ActivityRecord{529b601c u0 com.amqr.flagtest/.SecondActivity t54}
TaskRecord{52928e18 #53 A=com.amqr.flagtest U=0 sz=1}
Run #0: ActivityRecord{5297ded0 u0 com.amqr.flagtest/.FirstActivity t53}
也就是說,在步驟二的時(shí)候我們的頁面3川慌,也就是ThirdActivity在這個(gè)地方已經(jīng)是存放com.amqr.third333任務(wù)棧里面吃嘿,而且com.amqr.third333是前臺任務(wù)棧,在這種情況下我們進(jìn)行步驟三梦重,在頁面3再打開一次頁面3兑燥,這是沒有任何作用的。復(fù)用頂部琴拧,沒有新的實(shí)例產(chǎn)生贪嫂,需要注意的是,這種方式產(chǎn)生的任務(wù)棧只能存放一個(gè)Activity艾蓝。
步驟4:C打開B
Running activities (most recent first):
TaskRecord{52a6e690 #54 A=com.amqr.second222 U=0 sz=1}
Run #2: ActivityRecord{529b601c u0 com.amqr.flagtest/.SecondActivity t54}
TaskRecord{52b6a93c #55 A=com.amqr.third333 U=0 sz=1}
Run #1: ActivityRecord{52a8d5f8 u0 com.amqr.flagtest/.ThirdActivity t55}
TaskRecord{52928e18 #53 A=com.amqr.flagtest U=0 sz=1}
Run #0: ActivityRecord{5297ded0 u0 com.amqr.flagtest/.FirstActivity t53}
發(fā)現(xiàn)沒有產(chǎn)生新的任務(wù)棧,也有添加任務(wù)Activity斗塘。但是前臺任務(wù)棧改變了赢织,幾個(gè)任務(wù)棧的順序和前后臺關(guān)系產(chǎn)生了變化,com.amqr.second222由后臺任務(wù)棧變成了前臺任務(wù)棧馍盟。
每一個(gè)任務(wù)棧里面一個(gè)Activity于置,不增不減。
結(jié)論:Intent.FLAG_ACTIVITY_NEW_TASK + android:taskAffinity 指定非程序包名的任務(wù)棧名贞岭,?與清單文件里面指定 android:launchMode="singleInstance"效果一致
.
.
情景3:把所有的按鈕點(diǎn)擊事件的Intent的全部設(shè)定為Intent.FLAG_ACTIVITY_SINGLE_TOP八毯。
沒什么區(qū)別,這里就只貼一份FirstActivity的代碼就好了瞄桨,其他類似话速。反正改變的都是四份代碼的里面的全部的點(diǎn)擊事件的Intent的addFlag從Intent.FLAG_ACTIVITY_NEW_TASK改成Intent.FLAG_ACTIVITY_SINGLE_TOP。
結(jié)論先上: ** 設(shè)定Intent.FLAG_ACTIVITY_SINGLE_TOP與清單文件里面指定 android:launchMode="singleTop"效果一致芯侥。**
操作:A打開B泊交,再打開(復(fù)用乳讥,無新實(shí)例),B打開C廓俭,再代開C(復(fù)用云石,無新實(shí)例),C打開D研乒,D再開D(復(fù)用汹忠,無新實(shí)例)
FirstActivity代碼
public class FirstActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_first);
findViewById(R.id.mBtOpen2).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent openSecond = new Intent(FirstActivity.this, SecondActivity.class);
openSecond.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(openSecond);
}
});
findViewById(R.id.mBtOpen3).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent openThird = new Intent(FirstActivity.this, ThirdActivity.class);
openThird.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(openThird);
}
});
findViewById(R.id.mBtOpen4).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent openFourth = new Intent(FirstActivity.this, FourthActivity.class);
openFourth.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(openFourth);
}
});
}
}
這里我們就不貼終端了。一個(gè)gif說明一切雹熬。
從圖中我們可以看到宽菜,(我們的B路星,C和D頁面都是每次打開的都是Intent.FLAG_ACTIVITY_SINGLE_TOP的)萌丈,當(dāng)我們打開頁面B,之后强挫,想再次打次B仰楚,就沒有新的實(shí)例產(chǎn)生了隆判,而是復(fù)用了頂部的B。
C和D也是這種情況發(fā)生僧界。圖中也做了演示侨嘀。
而且在最后,我們發(fā)現(xiàn)當(dāng)我們從A打開B捂襟,從B打開C咬腕,再從C打開D,最后D打開B的時(shí)候葬荷,就又可以打開B了涨共,又有一個(gè)B的實(shí)例產(chǎn)生并且位于棧頂了。所以這一切的一切都是跟xml設(shè)定launchMode為singleTop完全一致的宠漩。
證明結(jié)論:設(shè)定Intent.FLAG_ACTIVITY_SINGLE_TOP與清單文件里面指定 android:launchMode="singleTop"效果一致举反。
情景4 把A、B和C頁面的按鈕的打開頁面的Intent都不設(shè)置addFlag扒吁,即ABC打開的頁面都是standard火鼻,然后頁面D的打開頁面B的Intent的addFlag都設(shè)定的Intent.FLAG_ACTIVITY_CLEAR_TOP,其他兩個(gè)按鈕不設(shè)置Flag雕崩。
先上結(jié)論:
結(jié)論1:Intent.FLAG_ACTIVITY_CLEAR_TOP與清單文件里面指定 android:launchMode="singleTask"效果類似魁索,只是類似。因?yàn)楫?dāng)初頂部的時(shí)候和android:launchMode="singleTask"產(chǎn)生很大的差別
(參考情景5我們就知道是區(qū)別在哪里了)
結(jié)論2: 代碼指定Flag(不單指FLAG_ACTIVITY_CLEAR_TOP)盼铁,使得Activity啟動模式可變粗蔚,而且最后一次指定的Flag就是該Activity在任務(wù)棧中最終啟動模式。
這個(gè)上代碼吧饶火,因?yàn)楹竺孢€要描述一些事情支鸡。
FirstActivity
public class FirstActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_first);
findViewById(R.id.mBtOpen2).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent openSecond = new Intent(FirstActivity.this, SecondActivity.class);
//openSecond.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(openSecond);
}
});
findViewById(R.id.mBtOpen3).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent openThird = new Intent(FirstActivity.this, ThirdActivity.class);
startActivity(openThird);
}
});
findViewById(R.id.mBtOpen4).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent openFourth = new Intent(FirstActivity.this, FourthActivity.class);
startActivity(openFourth);
}
});
}
}
.
.
SecondActivity
public class SecondActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
findViewById(R.id.mBtOpen2).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent openSecond = new Intent(SecondActivity.this, SecondActivity.class);
startActivity(openSecond);
}
});
findViewById(R.id.mBtOpen3).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent openThird = new Intent(SecondActivity.this, ThirdActivity.class);
startActivity(openThird);
}
});
findViewById(R.id.mBtOpen4).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent openFourth = new Intent(SecondActivity.this, FourthActivity.class);
startActivity(openFourth);
}
});
}
}
.
.
ThirdActivity
public class ThirdActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_third);
findViewById(R.id.mBtOpen2).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent openSecond = new Intent(ThirdActivity.this, SecondActivity.class);
startActivity(openSecond);
}
});
findViewById(R.id.mBtOpen3).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent openThird = new Intent(ThirdActivity.this, ThirdActivity.class);
startActivity(openThird);
}
});
findViewById(R.id.mBtOpen4).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent openFourth = new Intent(ThirdActivity.this, FourthActivity.class);
startActivity(openFourth);
}
});
}
}
.
.
FourthActivity
public class FourthActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fourth);
findViewById(R.id.mBtOpen2).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent openSecond = new Intent(FourthActivity.this, SecondActivity.class);
openSecond.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(openSecond);
}
});
findViewById(R.id.mBtOpen3).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent openThird = new Intent(FourthActivity.this, ThirdActivity.class);
startActivity(openThird);
}
});
findViewById(R.id.mBtOpen4).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent openFourth = new Intent(FourthActivity.this, FourthActivity.class);
startActivity(openFourth);
}
});
}
}
就是這樣冬念,其實(shí)目前只有在頁面D里面的用于打開頁面B的按鈕設(shè)置了Intent.FLAG_ACTIVITY_CLEAR_TOP的Flag
操作:我們啟動A,A啟動B牧挣,B啟動B急前,B再啟動C,C啟動D瀑构,再從D啟動B裆针。
分兩步走:
第一步:
我們啟動A,A啟動B寺晌,B再啟動C世吨,C啟動D,此時(shí)任務(wù)棧的里面的情況是DCBA呻征,其中D為棧頂耘婚。
Running activities (most recent first):
TaskRecord{52938abc #36 A=com.amqr.flagtest U=0 sz=4}
Run #3: ActivityRecord{52978c64 u0 com.amqr.flagtest/.FourthActivity t36}
Run #2: ActivityRecord{52946268 u0 com.amqr.flagtest/.ThirdActivity t36}
Run #1: ActivityRecord{52a8fd24 u0 com.amqr.flagtest/.SecondActivity t36}
Run #0: ActivityRecord{52a0a8b4 u0 com.amqr.flagtest/.FirstActivity t36}
第二步:再從D啟動B。
這時(shí)我們會發(fā)現(xiàn)陆赋,任務(wù)棧變成BA沐祷,其中B為棧頂,C和D都被B給干掉了攒岛。
Running activities (most recent first):
TaskRecord{52938abc #36 A=com.amqr.flagtest U=0 sz=2}
Run #1: ActivityRecord{52969568 u0 com.amqr.flagtest/.SecondActivity t36}
Run #0: ActivityRecord{52a0a8b4 u0 com.amqr.flagtest/.FirstActivity t36}
證明結(jié)論:Intent.FLAG_ACTIVITY_CLEAR_TOP與清單文件里面指定 android:launchMode="singleTask"效果類似赖临。(當(dāng)位于棧內(nèi)沒什么確實(shí)效果一致,當(dāng)位于棧頂就很不一樣了)
我們這里做了個(gè)實(shí)驗(yàn)灾锯。
我們看到代碼里我們的FirstActivity打SecondActivity的時(shí)候(就是A打開B的時(shí)候)兢榨,并沒有設(shè)定Intent的Flag,即A打開B的時(shí)候B在任務(wù)棧里面是屬于Standard模式的顺饮,但是在D打開B的時(shí)候吵聪,因?yàn)槲覀冎付ù蜷_B的時(shí)候B需要使用FLAG_ACTIVITY_CLEAR_TOP模式,所以這個(gè)時(shí)候就從Standard變成了FLAG_ACTIVITY_CLEAR_TOP(singleTask效果)了兼雄。
可見吟逝,代碼設(shè)定最大Flag好處就是啟動模式可變,而XML則是定死的君旦。
這里如果我們反過來,把上面代碼稍作修改嘲碱,把在A頁面打開B的時(shí)候把B設(shè)為FLAG_ACTIVITY_CLEAR_TOP金砍,然后D打開B不添加任何Flag(即為D打開的B為Standard),發(fā)現(xiàn)這樣設(shè)定之后麦锯,我們D打開B恕稠,結(jié)果是多產(chǎn)生了一個(gè)B的實(shí)例,而是不是B把D和C都給清掉扶欣。這就再一次證明最后設(shè)定開啟該Activity的模式其最終的啟動模式鹅巍。
結(jié)論證明 代碼指定Flag使得Activity啟動模式可變千扶,而且最后一次指定的Flag就是該Activity在任務(wù)棧中最終的模式。
情景5骆捧,把A打開B澎羞,B打開B的界面都設(shè)定為Intent.FLAG_ACTIVITY_CLEAR_TOP,然后A啟動B敛苇,B啟動B妆绞。
結(jié)論: 在一個(gè)打開時(shí)已經(jīng)被標(biāo)記為FLAG_ACTIVITY_CLEAR_TOP的界面(現(xiàn)正處于前臺任務(wù)棧的棧頂),如果我們在此界面打開自己枫攀,并且一樣標(biāo)記為FLAG_ACTIVITY_CLEAR_TOP括饶,那么這個(gè)時(shí)候會經(jīng)歷一次建新毀舊的過程,任務(wù)棧里面從結(jié)果的來說沒什么變化来涨,但是從生命周期的著眼于過程的角度來卻經(jīng)歷非常大的變化图焰。
步驟一:A打開B:
終端
Running activities (most recent first):
TaskRecord{52ac1a08 #61 A=com.amqr.flagtest U=0 sz=2}
Run #1: ActivityRecord{529e1994 u0 com.amqr.flagtest/.SecondActivity t61}
Run #0: ActivityRecord{529ca8e0 u0 com.amqr.flagtest/.FirstActivity t61}
生命周期
12-06 01:09:22.978 5768-5768/? D/Cur: FirstActivity onCreate
12-06 01:09:22.978 5768-5768/? D/Cur: FirstActivity onStart
12-06 01:09:22.978 5768-5768/? D/Cur: FirstActivity onResume
// A打開B
12-06 01:09:25.694 5768-5768/com.amqr.flagtest D/Cur: FirstActivity onPause
12-06 01:09:25.698 5768-5768/com.amqr.flagtest D/Cur: SecondActivity onCreate
12-06 01:09:25.698 5768-5768/com.amqr.flagtest D/Cur: SecondActivity onStart
12-06 01:09:25.698 5768-5768/com.amqr.flagtest D/Cur: SecondActivity onResume
12-06 01:09:26.090 5768-5768/com.amqr.flagtest D/Cur: FirstActivity onStop
在這里位置一切正常,下面發(fā)生的事情比較詭異
步驟二:B打開B蹦掐,這個(gè)是否發(fā)生的比較詭異技羔,不是復(fù)用,而是建立一個(gè)新的笤闯,毀滅舊的堕阔。
這里貼代碼非常有必要:
manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.amqr.flagtest" >
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme" >
<activity android:name=".FirstActivity" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".SecondActivity"
/>
<activity android:name=".ThirdActivity"
/>
<activity android:name=".FourthActivity"/>
</application>
</manifest>
FirstActivity
public class FirstActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_first);
Log.d("Cur", "FirstActivity onCreate");
findViewById(R.id.mBtOpen2).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent openSecond = new Intent(FirstActivity.this, SecondActivity.class);
openSecond.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(openSecond);
}
});
findViewById(R.id.mBtOpen3).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent openThird = new Intent(FirstActivity.this, ThirdActivity.class);
startActivity(openThird);
}
});
findViewById(R.id.mBtOpen4).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent openFourth = new Intent(FirstActivity.this, FourthActivity.class);
startActivity(openFourth);
}
});
}
@Override
protected void onStart() {
super.onStart();
Log.d("Cur", "FirstActivity onStart");
}
@Override
protected void onResume() {
super.onResume();
Log.d("Cur", "FirstActivity onResume");
}
@Override
protected void onPause() {
super.onPause();
Log.d("Cur", "FirstActivity onPause");
}
@Override
protected void onStop() {
super.onStop();
Log.d("Cur", "FirstActivity onStop");
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.d("Cur", "FirstActivity onDestroy");
}
@Override
protected void onRestart() {
super.onRestart();
Log.d("Cur", "FirstActivity onRestart");
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Log.d("Cur", "FirstActivity onNewIntent");
}
}
SecondActivity
public class SecondActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
Log.d("Cur","SecondActivity onCreate");
findViewById(R.id.mBtOpen2).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent openSecond = new Intent(SecondActivity.this, SecondActivity.class);
openSecond.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(openSecond);
}
});
findViewById(R.id.mBtOpen3).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent openThird = new Intent(SecondActivity.this, ThirdActivity.class);
startActivity(openThird);
}
});
findViewById(R.id.mBtOpen4).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent openFourth = new Intent(SecondActivity.this, FourthActivity.class);
startActivity(openFourth);
}
});
}
@Override
protected void onStart() {
super.onStart();
Log.d("Cur", "SecondActivity onStart");
}
@Override
protected void onResume() {
super.onResume();
Log.d("Cur", "SecondActivity onResume");
}
@Override
protected void onPause() {
super.onPause();
Log.d("Cur", "SecondActivity onPause");
}
@Override
protected void onStop() {
super.onStop();
Log.d("Cur", "SecondActivity onStop");
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.d("Cur", "SecondActivity onDestroy");
}
@Override
protected void onRestart() {
super.onRestart();
Log.d("Cur", "SecondActivity onRestart");
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Log.d("Cur", "SecondActivity onNewIntent");
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Log.d("Cur", "SecondActivity onSaveInstanceState");
}
}
.
.
看完了代碼,我們先來看一下gif圖颗味。
當(dāng)我們在 B 界面打開B的時(shí)候超陆,根據(jù)的頁面的閃一下的反饋我們感覺這時(shí)候一個(gè)重新創(chuàng)建了B的一個(gè)實(shí)例,那么按道理任務(wù)這時(shí)候的情況就是BBA浦马,B為棧頂时呀,A為棧底,如果照著這種想法那么我們此時(shí)按下back鍵應(yīng)該是返回到B界面晶默,任務(wù)棧變成BA谨娜,B為棧頂。
但是實(shí)際上發(fā)生的卻不是這個(gè)樣子的磺陡,實(shí)際上發(fā)生的事情卻是:
按下back鍵趴梢,直接返回A界面。
再按一次back鍵就退出了程序了币他。
這意味著什么坞靶?這意味我們的眼睛欺騙了我們,屏幕閃的那一下是創(chuàng)建的一個(gè)B的實(shí)例沒有錯(cuò)蝴悉,但是我們看不到的事情是在新建新的實(shí)例入棧的同時(shí)那么舊的B就被銷毀掉了彰阴。所以,當(dāng)我們屏幕閃一下之后拍冠,任務(wù)棧存在的是BA尿这,B為棧頂簇抵,而不是BBA。
終端顯示的是每沒打開之前一樣射众,沒有變化(因?yàn)樗皇怯涗涀詈蟮慕Y(jié)果碟摆,不管過程)
(此時(shí)顯示的是B打開B之后的狀態(tài),還沒按下back)
Running activities (most recent first):
TaskRecord{52ac1a08 #61 A=com.amqr.flagtest U=0 sz=2}
Run #1: ActivityRecord{52a0fb5c u0 com.amqr.flagtest/.SecondActivity t61}
Run #0: ActivityRecord{529ca8e0 u0 com.amqr.flagtest/.FirstActivity t61}
從生命周期的變化我們大概明白這一切是怎么發(fā)生的了责球。
12-06 01:09:22.978 5768-5768/? D/Cur: FirstActivity onCreate
12-06 01:09:22.978 5768-5768/? D/Cur: FirstActivity onStart
12-06 01:09:22.978 5768-5768/? D/Cur: FirstActivity onResume
// A打開B
12-06 01:09:25.694 5768-5768/com.amqr.flagtest D/Cur: FirstActivity onPause
12-06 01:09:25.698 5768-5768/com.amqr.flagtest D/Cur: SecondActivity onCreate
12-06 01:09:25.698 5768-5768/com.amqr.flagtest D/Cur: SecondActivity onStart
12-06 01:09:25.698 5768-5768/com.amqr.flagtest D/Cur: SecondActivity onResume
12-06 01:09:26.090 5768-5768/com.amqr.flagtest D/Cur: FirstActivity onStop
// B打開B 從生命周期我們發(fā)生了原因焦履,B在這里滅掉了自己,然后重建一個(gè)自己
12-06 01:11:50.390 5768-5768/com.amqr.flagtest D/Cur: SecondActivity onPause
12-06 01:11:50.410 5768-5768/com.amqr.flagtest D/Cur: SecondActivity onCreate
12-06 01:11:50.410 5768-5768/com.amqr.flagtest D/Cur: SecondActivity onStart
12-06 01:11:50.410 5768-5768/com.amqr.flagtest D/Cur: SecondActivity onResume
12-06 01:11:50.786 5768-5768/com.amqr.flagtest D/Cur: SecondActivity onStop
12-06 01:11:50.786 5768-5768/com.amqr.flagtest D/Cur: SecondActivity onDestroy
結(jié)論:設(shè)定為Intent.FLAG_ACTIVITY_CLEAR_TOP的Activity處于前臺任務(wù)棧棧頂時(shí)雏逾,如果在當(dāng)前頁面打開自己嘉裤,經(jīng)歷了一個(gè)建新毀舊的過程,算不上復(fù)用栖博。
(這個(gè)過程會創(chuàng)建一個(gè)新的實(shí)例屑宠,然后把舊的自己給銷毀掉,這個(gè)結(jié)果在任務(wù)棧的最終結(jié)果看來是沒變化的仇让,但是實(shí)際上生命周期卻發(fā)生了很大的變化典奉。)
結(jié)論:在一個(gè)打開時(shí)已經(jīng)被標(biāo)記為FLAG_ACTIVITY_CLEAR_TOP的界面(現(xiàn)正處于前臺任務(wù)棧的棧頂),如果我們在此界面打開自己丧叽,并且一樣標(biāo)記為FLAG_ACTIVITY_CLEAR_TOP卫玖,那么這個(gè)時(shí)候會經(jīng)歷一次建新毀舊的過程,沒有復(fù)用踊淳,任務(wù)棧里面從結(jié)果的來說沒什么變化假瞬,但是生命周期的著眼于過程的角度來卻經(jīng)歷非常大的變化。
本篇完迂尝。