1.為什么要使用啟動模式崇裁?
在我們的Android開發(fā)之中奔缠,當(dāng)我們多次啟動同一個Activity的時候,系統(tǒng)匯創(chuàng)將多個重復(fù)的實(shí)例氮块,將他們放到任務(wù)棧之中绍载。當(dāng)我們點(diǎn)擊返回鍵的時候,這些Activity實(shí)例又將從任務(wù)棧中一一移除滔蝉,遵循椈骼埽“后進(jìn)先出”的原則。
2.啟動模式的分類
1.默認(rèn)模式 Standard
說明: Android創(chuàng)建Activity時的默認(rèn)模式蝠引,假設(shè)沒有為Activity設(shè)置啟動模式的話阳谍,默覺得標(biāo)準(zhǔn)模式。每次啟動一個Activity都會又一次創(chuàng)建一個新的實(shí)例入棧螃概,無論這個實(shí)例是否存在矫夯。
生命周期:如上所看到的,每次被創(chuàng)建的實(shí)例Activity 的生命周期符合典型情況吊洼,它的onCreate训貌、onStart、onResume都會被調(diào)用。
-
在Manifest中配置:對于標(biāo)準(zhǔn)模式,android:launchMode=”standard”可以不寫递沪,因?yàn)槟J(rèn)就是standard模式豺鼻。
<activity
android:name=".StandardActivity"
android:launchMode="standard" >
</activity>
-
啟動Activity的時候。在Intent中指定啟動模式去創(chuàng)建Activity
通過Intent的addFlags方法去動態(tài)的指定一個啟動模式款慨。
Intent intent = new Intent();
intent.setClass(context, MainActivity.class);
context.startActivity(intent);
這時我們不需要去設(shè)置啟動Flags拘领,默認(rèn)就是standard啟動
2.SingleTop 棧頂復(fù)用模式
說明:分兩種處理情況:須要創(chuàng)建的Activity已經(jīng)處于棧頂時,此時會直接復(fù)用棧頂?shù)腁ctivity樱调。不會再創(chuàng)建新的Activity约素;若須要創(chuàng)建的Activity不處于棧頂,此時會又一次創(chuàng)建一個新的Activity入棧笆凌,同Standard模式一樣圣猎。
生命周期:若情況一中棧頂?shù)腁ctivity被直接復(fù)用時,它的onCreate乞而、onStart不會被系統(tǒng)調(diào)用送悔,由于它并沒有發(fā)生改變∽δ#可是一個新的方法 onNewIntent會被回調(diào)(Activity被正常創(chuàng)建時不會回調(diào)此方法)欠啤。
-
在 Manifest.xml中指定Activity啟動模式
<activity android:name="..activity.MultiportActivity" android:launchMode="singleTop"/>
-
啟動Activity時。在Intent中指定啟動模式去創(chuàng)建Activity
Intent intent = new Intent();
intent.setClass(context, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
context.startActivity(intent);
這里的FLAG_ACTIVITY_SINGLE_TOP就是我們設(shè)置的標(biāo)記位屋灌,作用就是為Activity指定“singleTop”啟動模式
3.棧內(nèi)復(fù)用模式
說明:若須要創(chuàng)建的Activity已經(jīng)處于棧中時洁段,此時不會創(chuàng)建新的Activity,而是將存在棧中的Activity上面的其他Activity所有銷毀共郭,使它成為棧頂祠丝。
生命周期:同SingleTop 模式中的情況一同樣。僅僅會又一次回調(diào)Activity中的 onNewIntent方法
-
在Manifest中配置:
<activity android:name="..activity.MultiportActivity" android:launchMode="singleTask"/>
-
啟動Activity時除嘹。在Intent中指定啟動模式去創(chuàng)建Activity
Intent intent = new Intent();
intent.setClass(context, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
這里的FLAG_ACTIVITY_NEW_TASK就是我們設(shè)置的標(biāo)記位写半,作用就是將Activity的啟動模式設(shè)置為singleTask
4.SingleInstance:單例模式的實(shí)現(xiàn)
-
在Manifest中配置:
<activity android:name="..activity.MultiportActivity" android:launchMode="singleTask"/>
這里的SingleInstance才是四種啟動模式中的重點(diǎn),它具備所有的SingleTask的特點(diǎn)尉咕,就是一種加強(qiáng)的singleTask叠蝇。但是和別的四種啟動模式不同的是:這種啟動模式會單獨(dú)的創(chuàng)建一個任務(wù)棧,上面的三種啟動模式都是存在于同一個任務(wù)棧之中年缎,而這種的模式存在于另一個任務(wù)棧之中悔捶。這樣的存在模式使用的時候可能存在這一些問題,下面我們在進(jìn)行分析晦款。
我們定義了ActivityA和ActivitySecond兩個界面
當(dāng)我們啟動ActivityA后:
點(diǎn)擊按鈕進(jìn)入ActivitySecond
當(dāng)我們退出去之后暫時退出去后炎功,重新進(jìn)入后返回的結(jié)果:
這里的原因是:當(dāng)我們重新進(jìn)入的時候,我們會重新的在主任務(wù)棧進(jìn)行查找缓溅,若沒有就會進(jìn)行創(chuàng)建蛇损,但是我們的SecondActivity在另外的一個任務(wù)棧之中,這樣當(dāng)我們使用了home鍵暫時的退出程序后再進(jìn)入,此時會調(diào)用主任務(wù)棧中棧頂Activity的onRestart淤齐,不會調(diào)
用SecondActivity的onRestart股囊。
想著查詢一些資料找到解決的辦法,但是后來發(fā)現(xiàn)其實(shí)這個問題根本不需要解決更啄。
因?yàn)槲覀兇藭r根本不需要將我們的launchMode設(shè)置為singleInstance稚疹,這樣的啟動模式只會運(yùn)用在一些特定的需要獨(dú)立棧操作的應(yīng)用上面。比如說:呼叫來電界面祭务。當(dāng)我們正在A應(yīng)用中看視頻的時候内狗,接收到來電,點(diǎn)擊進(jìn)入到來電詳情界面义锥,當(dāng)我們點(diǎn)擊返回之后就回到A視頻的界面柳沙,這樣就不會干擾到用戶之前的操作。
這個時候我們只會產(chǎn)生一個單獨(dú)運(yùn)行的Activity的界面拌倍,這個Activiyt會具有全局唯一性赂鲤,整個系統(tǒng)之中只會存在一個這樣的實(shí)例;
其實(shí)上面的呼叫來電的界面和我們的ActivitySecond界面大同小異柱恤,我們的ActivityA就相當(dāng)于上面的應(yīng)用A数初,只不過,當(dāng)我們退出通話界面的時候梗顺,系統(tǒng)會掛起通話界面也就是實(shí)現(xiàn)onPause泡孩,但是此時通話任務(wù)任然的進(jìn)行,通話界面之中雖然可以可以控制通話的結(jié)束荚守,但是兩者的生命周期卻是沒有進(jìn)行綁定珍德。當(dāng)我們的通話任務(wù)結(jié)束的時候才能夠?qū)νㄔ捊缑孢M(jìn)行銷毀。
這樣的功能都是可以在我們的ActivitySecond界面的基礎(chǔ)之上進(jìn)行實(shí)現(xiàn)矗漾。
3.復(fù)用Activity時的生命周期回調(diào)
由于當(dāng)一個Activity設(shè)置了SingleTop或者SingleTask模式后,跳轉(zhuǎn)此Activity出現(xiàn)復(fù)用原有Activity的情況時薄料,此Activity的onCreate方法將不會再次運(yùn)行敞贡。onCreate方法僅僅會在第一次創(chuàng)建Activity時被運(yùn)行。
而一般onCreate方法中會進(jìn)行該頁面的數(shù)據(jù)初始化摄职、UI初始化誊役,假設(shè)頁面的展示數(shù)據(jù)無關(guān)頁面跳轉(zhuǎn)傳遞的參數(shù),則不必操心此問題谷市,若頁面展示的數(shù)據(jù)就是通過getInten() 方法來獲取蛔垢,那么問題就會出現(xiàn):getInten()獲取的一直都是老數(shù)據(jù),根本無法接收跳轉(zhuǎn)時傳送的新數(shù)據(jù)迫悠!
public class CourseDetailActivity extends BaseActivity{
......
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_course_detail_layout);
initData();
initView();
}
//初始化數(shù)據(jù)
private void initData() {
Intent intent = getIntent();
mCourseID = intent.getStringExtra(COURSE_ID);
}
//初始化UI
private void initView() {
......
}
......
}
以上代碼中的CourseDetailActivity在配置文件里設(shè)置了啟動模式是SingleTop模式鹏漆,依據(jù)上面啟動模式的介紹可得知,當(dāng)CourseDetailActivity處于棧頂時。再次跳轉(zhuǎn)頁面到CourseDetailActivity時會直接復(fù)用原有的Activity艺玲,并且此頁面須要展示的數(shù)據(jù)是從getIntent()方法得來括蝠,可是initData()方法不會再次被調(diào)用,此時頁面就無法顯示新的數(shù)據(jù)饭聚。
當(dāng)然這樣的情況系統(tǒng)早就為我們想過了忌警,這時我們須要另外一個回調(diào) onNewIntent(Intent intent)方法。當(dāng)我們復(fù)用Activity的時候就會調(diào)用此方法秒梳,不復(fù)用就不會調(diào)用法绵。此方法會傳入最新的intent,這樣我們就能夠解決上述問題酪碘。這里建議的方法是又一次去setIntent礼烈。然后又一次去初始化數(shù)據(jù)和UI。代碼例如以下所看到的:
/*
* 復(fù)用Activity時的生命周期回調(diào)
*/
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
initData();
initView();
}
那么onNewIntent都會在什么情況下調(diào)用呢婆跑?
前提:ActivityA已經(jīng)啟動過,處于當(dāng)前應(yīng)用的Activity堆棧中;
當(dāng)ActivityA的LaunchMode為SingleTop時此熬,如果ActivityA在棧頂,且現(xiàn)在要再啟動ActivityA,這時會調(diào)用onNewIntent()方法
當(dāng)ActivityA的LaunchMode為SingleInstance,SingleTask時,如果已經(jīng)ActivityA已經(jīng)在堆棧中滑进,那么此時會調(diào)用onNewIntent()方法