一、生命周期
1.正常情況下生命周期分析
完整生命周期:onCreate -> onDestroy
可見生命周期:onStart -> onStop
前臺(tái)生命周期: onResume -> onPause
2.常見生命周期的區(qū)別
1. onCreate 和 onStart
(1)可見與不可見的區(qū)別。前者不可見,后者可見。
(2)onCreate方法只在Activity創(chuàng)建時(shí)執(zhí)行一次,而onStart方法在Activity的切換以及按Home鍵返回桌面再切回應(yīng)用的過程中被多次調(diào)用。
2.onStart 和 onRestart
如果一個(gè)activity第一次創(chuàng)建,那么只會(huì)走onStart,如果是切換應(yīng)用或者桌面,那么就會(huì)走onRestart
If it's destroyed onCreate(.) > onStart(.) > onResume(.) is called(variables are lost, redraw).
If it's stopped onRestart(.) > onStart(.) > onResume(.) is called(variables are not lost, redraw)
3.onStart 和 onResume
onStart activity 可見,不在前臺(tái)
onResume activity 可見,前臺(tái)且可與用戶交互
這2個(gè)的主要區(qū)別就是Activity此時(shí)是否可以與用戶交互
4.onPause 和 onStop
這2個(gè)狀態(tài)通常是配對(duì)執(zhí)行的,
有一種情況是特殊的,新啟動(dòng)的Activity是一個(gè)透明的界面,那么第一個(gè)Activity執(zhí)行onPause后,onStop是不會(huì)調(diào)用的
<activity android:name=".SecondActivity"
android:theme="@style/Theme.AppCompat.Dialog" />
5.onStop & onDestroy
onStop階段Activity還沒有被銷毀,對(duì)象還在內(nèi)存中,此時(shí)可以通過切換Activity再次回到該Activity,而onDestroy階段Activity被銷毀
tips:
不同的生命周期適合不同的資源初始化或者釋放工作,實(shí)踐和工作中多總結(jié)。http://www.lxweimin.com/p/fb44584daee3
3.常見操作的生命周期
1.Launcher點(diǎn)擊啟動(dòng)
01-16 10:57:22.429 26845-26845/? I/ActivityLife: onCreate...
01-16 10:57:22.429 26845-26845/? I/ActivityLife: onStart...
01-16 10:57:22.429 26845-26845/? I/ActivityLife: onResume...
2.back鍵退出
01-16 10:58:58.139 26845-26845/? I/ActivityLife: onPause...
01-16 10:58:58.459 26845-26845/? I/ActivityLife: onStop...
01-16 10:58:58.459 26845-26845/? I/ActivityLife: onDestroy...
3.HOME鍵退出然后再次點(diǎn)擊啟動(dòng)
01-16 10:59:49.019 26845-26845/? I/ActivityLife: onPause...
01-16 10:59:49.309 26845-26845/? I/ActivityLife: onStop...
01-16 11:00:06.519 26845-26845/? I/ActivityLife: onRestart...
01-16 11:00:06.519 26845-26845/? I/ActivityLife: onStart...
01-16 11:00:06.519 26845-26845/? I/ActivityLife: onResume...
4.鎖屏解鎖
01-16 11:02:33.739 26845-26845/? I/ActivityLife: onPause...
01-16 11:02:33.779 26845-26845/? I/ActivityLife: onStop...
01-16 11:02:35.509 26845-26845/? I/ActivityLife: onRestart...
01-16 11:02:35.529 26845-26845/? I/ActivityLife: onStart...
01-16 11:02:35.529 26845-26845/? I/ActivityLife: onResume...
2.異常情況下的生命周期分析
1.觸發(fā)情況:
1.系統(tǒng)資源相關(guān)的配置發(fā)生變化導(dǎo)致Activity被殺死和重建
2.系統(tǒng)內(nèi)存資源不足,lmk
2.執(zhí)行的特殊生命周期:
onSaveInstanceState & onRestoreInstanceState
1.onSaveInstanceState 通常在onStop之前,用于保存Activity數(shù)據(jù)
2.onRestoreInstanceState 通常在onStart之后,恢復(fù)Activity數(shù)據(jù)
tips:
在onCreate和onRestoreInstanceState中都有一個(gè)參數(shù)savedInstanceState,二者的區(qū)別是:onRestoreInstanceState的參數(shù)是一定有值的,我們不用額外的判斷它是否為空,但是onCreate不行,onCreate如果正常啟動(dòng)的話,savedInstanceState的值是null
3.典型示例,系統(tǒng)配置變化,屏幕旋轉(zhuǎn)
public class MainActivity extends AppCompatActivity {
private static final String TAG = "ActivityLife";
private static final String EDIT_TAG = "edit_tag";
private EditText editText;
@Override
protected void onSaveInstanceState(Bundle outState) {
Log.i(TAG, "onSaveInstanceState...");
super.onSaveInstanceState(outState);
String s = editText.getText().toString();
outState.putString(EDIT_TAG,s);
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
Log.i(TAG, "onRestoreInstanceState...");
//onCreate 或者這里恢復(fù)數(shù)據(jù)均可
editText.setText(savedInstanceState.getString(EDIT_TAG));
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.i(TAG, "onCreate...");
editText = (EditText) findViewById(R.id.edit_content);
if (savedInstanceState != null){
Log.i(TAG, "onCreate savedInstanceState is not null");
editText.setText(savedInstanceState.getString(EDIT_TAG));
}
}
}
從Lanucher啟動(dòng)并且旋轉(zhuǎn)一次屏幕,生命周期如下:
01-16 11:59:30.459 29726-29726/? I/ActivityLife: onCreate...
01-16 11:59:30.459 29726-29726/? I/ActivityLife: onStart...
01-16 11:59:30.459 29726-29726/? I/ActivityLife: onResume...
01-16 11:59:38.609 29726-29726/? I/ActivityLife: onPause...
01-16 11:59:38.609 29726-29726/? I/ActivityLife: onSaveInstanceState...
01-16 11:59:38.619 29726-29726/? I/ActivityLife: onStop...
01-16 11:59:38.619 29726-29726/? I/ActivityLife: onDestroy...
01-16 11:59:38.669 29726-29726/? I/ActivityLife: onCreate...
01-16 11:59:38.669 29726-29726/? I/ActivityLife: onCreate savedInstanceState is not null
01-16 11:59:38.669 29726-29726/? I/ActivityLife: onStart...
01-16 11:59:38.669 29726-29726/? I/ActivityLife: onRestoreInstanceState...
01-16 11:59:38.669 29726-29726/? I/ActivityLife: onResume...
4.onConfigurationChanged
當(dāng)系統(tǒng)配置發(fā)生變化,如果不希望Activity重新創(chuàng)建,可以在AndroidManifest文件中給Activity加上屬性,以屏幕旋轉(zhuǎn)為例
android:configChanges="orientation|screenSize"
注意:從 Android 3.2(API 級(jí)別 13)開始,當(dāng)設(shè)備在縱向和橫向之間切換時(shí),“屏幕尺寸”也會(huì)發(fā)生變化。因此,在開發(fā)針對(duì) API 級(jí)別 13 或更高版本(正如 minSdkVersion 和 targetSdkVersion 屬性中所聲明)的應(yīng)用時(shí),若要避免由于設(shè)備方向改變而導(dǎo)致運(yùn)行時(shí)重啟,則除了 "orientation" 值以外,您還必須添加 "screenSize" 值。 也就是說,您必須聲明 android:configChanges="orientation|screenSize"。
configChanges相關(guān)屬性
二、Activity的啟動(dòng)模式
1.Activity的四種啟動(dòng)模式
standard:標(biāo)準(zhǔn)模式,每次啟動(dòng)一個(gè)Activity都會(huì)重新創(chuàng)建一個(gè)新的實(shí)例,不管這個(gè)實(shí)例是否已經(jīng)存在
singleTop:棧頂復(fù)用模式,如果新的Activity已經(jīng)位于任務(wù)棧的棧頂,那么此Activity就不會(huì)被重新創(chuàng)建,同時(shí)他的onNewIntent方法會(huì)被回調(diào)
singleTask:棧內(nèi)復(fù)用模式,如果一個(gè)Activity在一個(gè)任務(wù)棧內(nèi)存在,那么多次啟動(dòng)這個(gè)Activity都不會(huì)重新創(chuàng)建實(shí)例,它的onNewIntent方法也會(huì)被回調(diào)
singleInstance:?jiǎn)螌?shí)例模式,具有此種模式的Activity只能單獨(dú)的位于一個(gè)任務(wù)棧中
standard 和 singleTop都比較好理解,下面主要分析下singleTask和singleInstance的特點(diǎn)。會(huì)用到的調(diào)試命令:
adb shell dumpsys activity | grep com.example.sven.activitydemo
2.singleTask的特點(diǎn)
1.singleTask 和 taskAffinity
1.launchMode=singleTask 的應(yīng)用啟動(dòng)時(shí)是否會(huì)創(chuàng)建新的任務(wù)和taskAffinity屬性有關(guān)
設(shè)置了"singleTask"啟動(dòng)模式的Activity,它在啟動(dòng)的時(shí)候,會(huì)先在系統(tǒng)中查找屬性值affinity等于它的屬值taskAffinity的任務(wù)存在;如果存在這樣的任務(wù),它就會(huì)在這個(gè)任務(wù)中啟動(dòng),否則就會(huì)在新任務(wù)中啟動(dòng)。因此如果我們想要設(shè)置了"singleTask"啟動(dòng)模式的Activity在新的任務(wù)中啟動(dòng),就要為它設(shè)置一個(gè)唯一的taskAffinity屬性值。
示例:A應(yīng)用中,A0(表示啟動(dòng)界面,A1跳轉(zhuǎn)的第二個(gè)界面,依次類推)A0-A1
(1)設(shè)置SecondActivity launchMode="singleTask",但不指定taskAffinity
TaskRecord{576dbde #53 A=com.example.sven.activitydemo U=0 sz=2}
Run #5: ActivityRecord{dc04be8 u0 com.example.sven.activitydemo/.SecondActivity t53}
Run #4: ActivityRecord{bebf9d2 u0 com.example.sven.activitydemo/.MainActivity t53}
可以看到,雖然設(shè)置了singleTask的lanuchModel,但是MainActivity和SecondActivity還是在同一個(gè)任務(wù)棧中
(2)設(shè)置SecondActivity launchMode="singleTask" ,同時(shí)指定taskAffinity = "com.example.sven.activitydemo.second"
TaskRecord{705495 #55 A=com.example.sven.activitydemo.second U=0 sz=1}
Run #5: ActivityRecord{5a9b163 u0 com.example.sven.activitydemo/.SecondActivity t55}
TaskRecord{9d799aa #54 A=com.example.sven.activitydemo U=0 sz=1}
Run #4: ActivityRecord{5e9adf5 u0 com.example.sven.activitydemo/.MainActivity t54}
可以看到,設(shè)置了taskAffinity后,新的Activity就運(yùn)行在新的任務(wù)棧里了
tips:
默認(rèn)情況下,所有Activity的所需任務(wù)棧名均為包名,所以說如果將上面的taskAffinity屬性設(shè)置為包名,SecondActivity也是不會(huì)在新的任務(wù)棧中啟動(dòng)的
2.在同一個(gè)任務(wù)棧中具有唯一性
如果設(shè)置了"singleTask"啟動(dòng)模式的Activity不是在新的任務(wù)中啟動(dòng)時(shí),它會(huì)在已有的任務(wù)中查看是否已經(jīng)存在對(duì)應(yīng)的Activity實(shí)例,如果存在,就會(huì)把位于這個(gè)Activity實(shí)例上面的Activity全部結(jié)束掉,最終這個(gè)Activity實(shí)例位于任務(wù)的堆棧頂端中。
示例:
MainActity SecondActivty ThirdActivty(以上3個(gè)Activity用A、B、C代表)在2種條件下執(zhí)行如下過程 A -> B ->C -> A ->B
(1) SecondActivty launchMode="singleTask",taskAffinity=包名,最終棧中的結(jié)果如下
TaskRecord{8d620aa #62 A=com.example.sven.activitydemo U=0 sz=2}
Run #5: ActivityRecord{ab051c1 u0 com.example.sven.activitydemo/.SecondActivity t62}
Run #4: ActivityRecord{56fcc63 u0 com.example.sven.activitydemo/.MainActivity t62}
(2) 設(shè)置SecondActivty 指定 taskAffinity = "com.example.sven.activitydemo.second"
TaskRecord{4e4a3bc #61 A=com.example.sven.activitydemo.second U=0 sz=1}
Run #5: ActivityRecord{f48dc2b u0 com.example.sven.activitydemo/.SecondActivity t61}
TaskRecord{ea52f45 #60 A=com.example.sven.activitydemo U=0 sz=1}
Run #4: ActivityRecord{9e4ab1 u0 com.example.sven.activitydemo/.MainActivity t60}
可以看到在2種情況下, 不論是否設(shè)定taskAffinity,在SecondActivity棧頂?shù)膶?shí)例都被清掉了
3.任務(wù)(Task)不僅可以跨應(yīng)用(Application),還可以跨進(jìn)程(Process)
示例:
2個(gè)應(yīng)用中A,B中,2個(gè)ActivityA1,B1的singleTask的Activity的taskAffinity設(shè)置為相同,執(zhí)行如下過程 A0->A1,B0->B1
android:launchMode="singleTask"
android:taskAffinity="com.example.sven.activitydemo.second"
TaskRecord{a412e6e #71 A=com.example.sven.activitydemo.second U=0 sz=2}
Run #5: ActivityRecord{12bc505 u0 com.example.sven.activitydemo2/.SecondActivityCopy t71}
TaskRecord{fa790f #72 A=com.example.sven.activitydemo2 U=0 sz=1}
Run #4: ActivityRecord{2610bd9 u0 com.example.sven.activitydemo2/.MainActivityCopy t72}
TaskRecord{a412e6e #71 A=com.example.sven.activitydemo.second U=0 sz=2}
Run #3: ActivityRecord{ca0064a u0 com.example.sven.activitydemo/.SecondActivity t71}
TaskRecord{c224d9c #70 A=com.example.sven.activitydemo U=0 sz=1}
Run #2: ActivityRecord{4257b8e u0 com.example.sven.activitydemo/.MainActivity t70}
可以看到相同taskAffinity的Run#5和Run#3是在同一個(gè)任務(wù)棧a412e6e中的。
tips:
Application,Task和Process的區(qū)別與聯(lián)系
application翻譯成中文時(shí)一般稱為“應(yīng)用”或“應(yīng)用程序”,在android中,總體來說一個(gè)應(yīng)用就是一組組件的集合。
task是在程序運(yùn)行時(shí),只針對(duì)activity的概念。說白了,task是一組相互關(guān)聯(lián)的activity的集合,它是存在于framework層的一個(gè)概念,控制界面的跳轉(zhuǎn)和返回。這個(gè)task存在于一個(gè)稱為backstack的數(shù)據(jù)結(jié)構(gòu)中,也就是說,framework是以棧的形式管理用戶開啟的activity。這個(gè)棧的基本行為是,當(dāng)用戶在多個(gè)activity之間跳轉(zhuǎn)時(shí),執(zhí)行壓棧操作,當(dāng)用戶按返回鍵時(shí),執(zhí)行出棧操作。
process一般翻譯成進(jìn)程,進(jìn)程是操作系統(tǒng)內(nèi)核中的一個(gè)概念,表示直接受內(nèi)核調(diào)度的執(zhí)行單位。在應(yīng)用程序的角度看,我們用java編寫的應(yīng)用程序,運(yùn)行在dalvik虛擬機(jī)中,可以認(rèn)為一個(gè)運(yùn)行中的dalvik虛擬機(jī)實(shí)例占有一個(gè)進(jìn)程,所以,在默認(rèn)情況下,一個(gè)應(yīng)用程序的所有組件運(yùn)行在同一個(gè)進(jìn)程中。但是這種情況也有例外,即,應(yīng)用程序中的不同組件可以運(yùn)行在不同的進(jìn)程中。只需要在manifest中用process屬性指定組件所運(yùn)行的進(jìn)程的名字。如下所示:
<activity
android:name=".SecondActivityCopy"
android:process=":remote"
android:allowTaskReparenting="true" />
4.allowTaskReparenting
一個(gè)應(yīng)用A啟動(dòng)另一個(gè)應(yīng)用B的B1(standard模式)Activity,如果這個(gè)Activity的allowTaskReparenting屬性為true的話,那么B啟動(dòng)后B1直接會(huì)轉(zhuǎn)移到B的任務(wù)棧中。現(xiàn)象就是A啟動(dòng)B1,在啟動(dòng)B時(shí),顯示的就是B1,而不是B0
A -> B1:
TaskRecord{fc84b0d #46 A=com.example.sven.activitydemo2 U=0 sz=1}
Run #1: ActivityRecord{8ebbcf3 u0 com.example.sven.activitydemo2/.SecondActivityCopy t46}
TaskRecord{137b068 #45 A=com.example.sven.activitydemo U=0 sz=1}
Run #0: ActivityRecord{b7827ad u0 com.example.sven.activitydemo/.MainActivity t45}
啟動(dòng)B
TaskRecord{fc84b0d #46 A=com.example.sven.activitydemo2 U=0 sz=1}
Run #1: ActivityRecord{8ebbcf3 u0 com.example.sven.activitydemo2/.SecondActivityCopy t46}
TaskRecord{137b068 #45 A=com.example.sven.activitydemo U=0 sz=1}
Run #0: ActivityRecord{b7827ad u0 com.example.sven.activitydemo/.MainActivity t45}
4.SingleInstance的特點(diǎn)
1.singleInstance模式啟動(dòng)的Activity具有全局唯一性
整個(gè)系統(tǒng)中只會(huì)存在一個(gè)這樣的實(shí)例,如果在啟動(dòng)這樣的Activity時(shí),已經(jīng)存在了一個(gè)實(shí)例,那么會(huì)把它所在的任務(wù)調(diào)度到前臺(tái),重用這個(gè)實(shí)例。
示例:
2 個(gè)應(yīng)用A,B,設(shè)置B1 launchMode="singleInstance", 執(zhí)行如下過程,先B -> B1, 再A0 ->B1
TaskRecord{9b9bb06 #108 A=com.example.sven.activitydemo2 U=0 sz=1}
Run #3: ActivityRecord{5520232 u0 com.example.sven.activitydemo2/.SecondActivityCopy t108}
TaskRecord{7b4a5c7 #107 A=com.example.sven.activitydemo2 U=0 sz=1}
Run #2: ActivityRecord{6cf92f7 u0 com.example.sven.activitydemo2/.MainActivityCopy t107}
TaskRecord{9b9bb06 #108 A=com.example.sven.activitydemo2 U=0 sz=1}
Run #4: ActivityRecord{5520232 u0 com.example.sven.activitydemo2/.SecondActivityCopy t108}
TaskRecord{3cccdb5 #109 A=com.example.sven.activitydemo U=0 sz=1}
Run #3: ActivityRecord{facfdb u0 com.example.sven.activitydemo/.MainActivity t109}
TaskRecord{7b4a5c7 #107 A=com.example.sven.activitydemo2 U=0 sz=1}
Run #2: ActivityRecord{6cf92f7 u0 com.example.sven.activitydemo2/.MainActivityCopy t107}
可以看到 2 個(gè)過程中B1 的Taskrecord沒有發(fā)生變化
2.singleInstance模式啟動(dòng)的Activity具有獨(dú)占性
它會(huì)獨(dú)自占用一個(gè)任務(wù),被他開啟的任何activity都會(huì)運(yùn)行在其他任務(wù)中,但是否能夠開啟一個(gè)新任務(wù),要看當(dāng)前系統(tǒng)中是不是已經(jīng)有了一個(gè)和要開啟的Activity的taskAffinity屬性相同的任務(wù)。
示例:
B0->B1 B1->A3(B0和B1又因?yàn)樯蟼€(gè)原則,所以是在不同的任務(wù)棧中)
TaskRecord{94de3cf #69 A=com.example.sven.activitydemo U=0 sz=1}
Run #2: ActivityRecord{89ba288 u0 com.example.sven.activitydemo/.ThirdActivity t69}
TaskRecord{2ad415c #68 A=com.example.sven.activitydemo2 U=0 sz=1}
Run #1: ActivityRecord{73d6ca u0 com.example.sven.activitydemo2/.SecondActivityCopy t68}
TaskRecord{6d70c65 #67 A=com.example.sven.activitydemo2 U=0 sz=1}
Run #0: ActivityRecord{3941c44 u0 com.example.sven.activitydemo2/.MainActivityCopy t67}
先啟動(dòng)A0(A3和A0是運(yùn)行在同一個(gè)棧中) B0->B1 B1->A3
TaskRecord{5db49f9 #71 A=com.example.sven.activitydemo U=0 sz=2}
Run #3: ActivityRecord{dfea174 u0 com.example.sven.activitydemo/.ThirdActivity t71}
TaskRecord{e7e8d3e #73 A=com.example.sven.activitydemo2 U=0 sz=1}
Run #2: ActivityRecord{cb12857 u0 com.example.sven.activitydemo2/.SecondActivityCopy t73}
TaskRecord{3f750ec #72 A=com.example.sven.activitydemo2 U=0 sz=1}
Run #1: ActivityRecord{2efad8b u0 com.example.sven.activitydemo2/.MainActivityCopy t72}
TaskRecord{5db49f9 #71 A=com.example.sven.activitydemo U=0 sz=2}
Run #0: ActivityRecord{c39fdab u0 com.example.sven.activitydemo/.MainActivity t71}
可以看到A3(Run #2)會(huì)在A0 (Run #5)的任務(wù)棧中46bac8a
tips:
啟動(dòng)時(shí)是否開啟任務(wù)棧,考慮3個(gè)點(diǎn):1.被啟動(dòng)的Activity的launchModel,如果是singleTask要同時(shí)考慮它的taskAffinity
2.啟動(dòng)Activity的launchmode(singleInstance)
3.當(dāng)前是否有被啟動(dòng)應(yīng)用的任務(wù)棧
4.Activity的flag
1.Intent.FLAG_ACTIVITY_NEW_TASK
等價(jià)于 launchMode = singleTask
2.Intent.FLAG_ACTIVITY_SINGLE_TOP
等價(jià)于 launchMode = singleTop 設(shè)置singleTop 和一起使用taskAffinity ,只有singleTop的效果
3.Intent.FLAG_ACTIVITY_CLEAR_TOP
檢查目標(biāo)棧中是否有對(duì)應(yīng)的實(shí)例,如果有就會(huì)將該實(shí)例之上的所有棧都清掉
A-B(正常啟動(dòng))->C->A->B(clearTop方式啟動(dòng))
(1) B的launchmode 是standard
TaskRecord{fec37c7 #134 A=com.example.sven.activitydemo U=0 sz=4}
Run #5: ActivityRecord{91e286b u0 com.example.sven.activitydemo/.MainActivity t134}
Run #4: ActivityRecord{775d8ae u0 com.example.sven.activitydemo/.ThirdActivity t134}
Run #3: ActivityRecord{20304d6 u0 com.example.sven.activitydemo/.SecondActivity t134}
Run #2: ActivityRecord{b049afa u0 com.example.sven.activitydemo/.MainActivity t134}
TaskRecord{fec37c7 #134 A=com.example.sven.activitydemo U=0 sz=2}
Run #3: ActivityRecord{4fdc1db u0 com.example.sven.activitydemo/.SecondActivity t134}
Run #2: ActivityRecord{b049afa u0 com.example.sven.activitydemo/.MainActivity t134}
可以看到,如果被啟動(dòng)的SecondActivity的啟動(dòng)模式是standard,那么B會(huì)重新創(chuàng)建新的實(shí)例并且之前的實(shí)例及實(shí)例之上的Activity都會(huì)出棧
(2) B的launchmode是singleTask
TaskRecord{249ecaa #135 A=com.example.sven.activitydemo U=0 sz=4}
Run #5: ActivityRecord{1116cb u0 com.example.sven.activitydemo/.MainActivity t135}
Run #4: ActivityRecord{92b068e u0 com.example.sven.activitydemo/.ThirdActivity t135}
Run #3: ActivityRecord{96bd6b6 u0 com.example.sven.activitydemo/.SecondActivity t135}
Run #2: ActivityRecord{44bf730 u0 com.example.sven.activitydemo/.MainActivity t135}
TaskRecord{249ecaa #135 A=com.example.sven.activitydemo U=0 sz=2}
Run #3: ActivityRecord{96bd6b6 u0 com.example.sven.activitydemo/.SecondActivity t135}
Run #2: ActivityRecord{44bf730 u0 com.example.sven.activitydemo/.MainActivity t135}
可以看到,如果被啟動(dòng)的SecondActivity的啟動(dòng)模式是SingleTask,那么B會(huì)清除實(shí)例之上的Activity,并且調(diào)用onNewIntent方法
總結(jié):主要2個(gè)點(diǎn),清除被啟動(dòng)Activity之上的實(shí)例,是否創(chuàng)建新的實(shí)例和被啟動(dòng)Activity的lanuchMode有關(guān)
4. Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
具有這個(gè)標(biāo)記的Activity不會(huì)出現(xiàn)在歷史Activity的記錄中,和android:excludeFromRecents作用相同
tips:?jiǎn)?dòng)模式有2種設(shè)置方法,通過設(shè)置Intent的FLAG 和 AndroidManifest.xml ,第一種方式的優(yōu)先級(jí)大于第二種方式
三、IntentFilter的匹配規(guī)則
Activity的顯示調(diào)用和隱式調(diào)用:http://blog.csdn.net/xiao__gui/article/details/11392987
一個(gè)activity可以有多個(gè)過濾器,每個(gè)過濾器均可以有多個(gè)action,category和data
1.action的匹配規(guī)則
Intent 中的 action 只要有一個(gè)與過濾器(manifest中的intent-filter)的匹配,就可調(diào)用這個(gè)過濾器所在的組件。
2.category的匹配規(guī)則
category 表示類別,最常見就是這2個(gè)
<category android:name="android.intent.category.LAUNCHER" />
<category android:name="android.intent.category.DEFAULT" />
1. 隱式啟動(dòng)時(shí)intent會(huì)自動(dòng)的添加一個(gè)默認(rèn)的category,所以隱式啟動(dòng)時(shí),過濾器中的默認(rèn)的category必須要加
<category android:name="android.intent.category.DEFAULT"/>
2. 隱式啟動(dòng)時(shí),intent中添加的category必須包含在過濾器中
3.data的匹配規(guī)則
data 表示該組件可以支持的數(shù)據(jù)格式與類型,intent 至少可以匹配過濾器中的一個(gè)
主要由兩部分組成:1.mimeType 2.URI ,語法如下:
<data android:scheme="string"
android:host="string"
android:port="string"
android:path="string"
android:pathPattern="string"
android:pathPrefix="string"
android:mimeType="string" />
(1) mimeType 指的是支持的數(shù)據(jù)類型與格式
常見的有:1.text/plain 2.image/jpeg 3.video/* 4.audio/*
/ 號(hào)前面的是數(shù)據(jù)類型,后面是具體格式。
(2) URI 格式:
<scheme>://<host>:<port>/[<path>]|[<pathPrefix>]|[pathPattern]
1.scheme、host、port、path分別表示URI的模式、主機(jī)名和端口號(hào)和路徑
例如:http://www.baidu.com:80/search/info
2.如果scheme或者h(yuǎn)ost未指定那么URI就無效
3.URI 是有默認(rèn)值的,content 和 file,這里不是很理解,不過發(fā)現(xiàn)這樣一種情況:
在intent-filter 中添加任意一種mimeType,不指定URI
<data android:mimeType="image/jpeg"/>
intent啟動(dòng)時(shí),設(shè)置URI為 content:.* 或 file:.* 均可啟動(dòng)
intent.setDataAndType(Uri.parse("content://abc"), "image/jpeg");
4.data 是有如下2種寫法的,效果是一樣的
<data android:scheme="file"
android:host="abc"
android:mimeType="text/plain"/>
<data android:scheme="file"/>
<data android:host="abc"/>
<data android:mimeType="text/plain"/>
如果一個(gè)intent-filter 中有多個(gè)data 并且他們的URI均不同,建議用第一種。
data 的匹配規(guī)則這里只列舉的常用的一部分,還有些情況類似與如下,也可以匹配到,可以將URI 和MIMETYPE的關(guān)理解為action和category的關(guān)系
<data android:scheme="http" android:host="abc" android:mimeType="text/plain"/>
<data android:scheme="http" android:host="abc2" android:mimeType="image/png"/>
intent.setDataAndType(Uri.parse("http://abc"), "image/png");
只能理解為 URI 和MIMETYPE 其實(shí)類似于 action 和 category的關(guān)系,采用如下的寫法更能表現(xiàn)兩者的關(guān)系,具體大家在實(shí)踐中多多理解
<data android:scheme="file" android:host="abc" />
<data android:scheme="file" android:host="abc2" />
<data android:mimeType="text/plain" />
<data android:mimeType="image/png" />
tips:
1.如果要為Intent指定完整的data,必須要調(diào)用setDataAndType方法,不能先調(diào)用setData然后調(diào)用setType,因?yàn)檫@兩個(gè)方法會(huì)彼此清除對(duì)方的值。
2.當(dāng)我們啟動(dòng)Activity可以通過resolveActivity判斷是否有對(duì)應(yīng)的Activity
if(this.getPackageManager().resolveActivity(intent, 0) != null){
startActivity(intent);
}
3.特殊的一組action和category,標(biāo)記應(yīng)用啟動(dòng)時(shí)打開的Activity,少了任何一個(gè)都沒有意義
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
4.顯示Component調(diào)用也是可以跨應(yīng)用的,需要顯示指定Activity屬性 android:exported="true" 或者添加一個(gè)intent-Filter,否則會(huì)報(bào)AndroidRuntime異常,通過Tip 3是不能檢查出intent是否正常。
以上這些自己寫了個(gè)Demo,方便大家調(diào)試和學(xué)習(xí):
http://download.csdn.net/detail/time_traveller14/9880456
http://download.csdn.net/detail/time_traveller14/9880457
問題:
- onSaveInstanceState 為何會(huì)在跳轉(zhuǎn)到別的Activity、Home鍵以及鎖屏?xí)r調(diào)用?
- category 和 data 的更多用法?
參考資料:
https://developer.android.com/reference/android/app/Activity.html
https://developer.android.com/guide/topics/manifest/activity-element.html?hl=zh-cn#config
http://blog.csdn.net/u011240877/article/details/71305797
《Android 開發(fā)藝術(shù)之旅》