
初識Activity:
我們都知道android中有四大組件(Activity活動,Service服務(wù),Content Provider內(nèi)容提供者,BroadcastReceiver廣播接收者),Activity是我們用的最多的,也是最為基本的組件,因?yàn)閼?yīng)用的所有操作都與用戶相關(guān),Activity提供窗口來和用戶進(jìn)行交互。
官方文檔這么說:
An activity is a single, focused thing that the user can do. Almost all activities interact with the user, so the Activity class takes care of creating a window for you in which you can place your UI with setContentView(View).
大概意思:activity是一個獨(dú)立的,能夠單獨(dú)處理用戶操作的組件,幾乎所有的activity都是用來和用戶做交互的,所以activity類會創(chuàng)建一個窗口,開發(fā)者可以通過setContent(View)的接口方法把UI放到activity組件上。
Android中activity全都?xì)w屬于task管理。task:是一個activity的集合,這些activity按照啟動的順序排隊(duì)存入一個棧(即"back stack")。android默認(rèn)會為每一個App維持一個task來存放該app的所有的activity,task的默認(rèn)name為該app的packagename。
Activity的內(nèi)部調(diào)用過程:
上面已經(jīng)講過了,系統(tǒng)通過堆棧來管理activity,當(dāng)一個新的activity開始時(shí),它被放置在堆棧的頂部和成為運(yùn)行活動,以前的activity始終保持低于它在堆棧的位置(也就是說當(dāng)前活動的activity位于棧頂,以前使用過的activity位于棧低)而不會再一次到達(dá)前臺,直到新的活動退出。

下面分析Activity的生命周期過程:
- ** 啟動Activity:** onCreate() -> onstart() -> onResume(),Activity進(jìn)入運(yùn)行狀態(tài)。
- Activity退居后臺:當(dāng)前Activity轉(zhuǎn)到新的Activity界面或者按手機(jī)Home鍵回到主屏:onPause() -> onStop(),進(jìn)入停滯狀態(tài)。
- Activity從后臺返回前臺:onRestart() -> onStart() -> onResume(),再次回到運(yùn)行狀態(tài)。
- Activity退居后臺,且系統(tǒng)內(nèi)存不足時(shí),系統(tǒng)會殺掉這個后臺轉(zhuǎn)態(tài)的Activity(此時(shí)這個Activity引用仍然處在任務(wù)棧中,只是這個時(shí)候引用指向的對象已經(jīng)為null),若再次回到這個Activity,則會走onCreate() -> onStart() -> onResume()(將重新走一次Activity的初始化生命周期)。
- 鎖屏:onPause() -> onStop()
- 解鎖:onStart() -> onResume()
- Activity的完整生存期會在onCreate()調(diào)用和onDestroy()調(diào)用之間發(fā)生。
- Activity的可見生存期會在onStart()調(diào)用和onStop()調(diào)用之間發(fā)生。系統(tǒng)會在activity的整個生存期內(nèi)多次調(diào)用onStart()和onStop(),因?yàn)閍ctivity可能會在顯示和隱藏之間不斷的來回切換。
- Activity的前后臺切換會在onResume()調(diào)用和onPause()調(diào)用之間發(fā)生。因?yàn)檫@個狀態(tài)可能會經(jīng)常發(fā)生轉(zhuǎn)換,為了避免切換遲緩引起的用戶等待,這兩個方法中的代碼應(yīng)該相當(dāng)?shù)剌p量化。
啟動模式是什么?為什么要定義啟動模式呢?
簡單的說啟動模式就是定義activity實(shí)例與task的關(guān)聯(lián)方式。
定義啟動模式是為了實(shí)現(xiàn)一些默認(rèn)啟動(standard)模式之外的需求:
1.讓某個activity啟動一個嶄新的task(而不是被放入到當(dāng)前的task中)
2.讓activity啟動時(shí)只是調(diào)出已有的某個實(shí)例(而不是在back stack棧頂創(chuàng)建一個嶄新的實(shí)例)
3.或者,你想在用戶離開task時(shí),只保留根activity,而back stack中的其他activity都要清空。
以上的這些需求,就是啟動模式,所起到的作用。
怎樣定義啟動模式?
定義啟動模式的方法有兩種:
1.在manifest 文件中,通過Acitivty的xml標(biāo)簽來改變?nèi)蝿?wù)棧的默認(rèn)行為(啟動模式):
- 使用
android:launchMode="standard|singleInstance|singleTask|singleTop"來控制Activity任務(wù)棧。在 manifest 文件中activity聲明時(shí),利用 activity 元素的 launchMode 屬性來設(shè)定 activity 與 task 的關(guān)系。
** 任務(wù)棧 是一種后進(jìn)先出的結(jié)構(gòu)。位于棧頂?shù)腁ctivity處于焦點(diǎn)狀態(tài),當(dāng)按下back按鈕的時(shí)候,棧內(nèi)的Activity會一個一個的出棧,并且調(diào)用其onDestory()方法。如果棧內(nèi)沒有Activity,那么系統(tǒng)就會回收這個棧,每個App默認(rèn)只有一個棧,以App的包名來命名。
** <1>.standard : 標(biāo)準(zhǔn)模式,每次啟動Activity都會創(chuàng)建一個新的Activity實(shí)例,并且將其壓入任務(wù)棧棧頂,而不管這個Activity是否已經(jīng)存在。Activity的啟動三回調(diào)(onCreate() -> onStart() -> onResume()都會執(zhí)行)。
** <2>.singleTop :** 棧頂復(fù)用模式,這種模式下,如果新Activity已經(jīng)位于任務(wù)棧的棧頂,那么此Activity不會被重新創(chuàng)建,所以它的啟動三回調(diào)就不會執(zhí)行,同時(shí)Activity的onNewIntent()方法會被回調(diào),如果Activity已經(jīng)存在但是不在棧頂,那么作用與standard模式一樣。
** <3>.singleTask:** 棧內(nèi)復(fù)用模式,創(chuàng)建這樣的Activity的時(shí)候,系統(tǒng)會先確認(rèn)它所需任務(wù)棧已經(jīng)創(chuàng)建,否則先創(chuàng)建任務(wù)棧,然后放入Activity,如果棧中已經(jīng)有一個Activity實(shí)例,那么這個Activity就會被調(diào)到棧頂,onNewIntent(),并且singleTask會清理在當(dāng)前Activity尚明的所有Activity。(clear top)
** <4>.singleInstance :**加強(qiáng)版的singleTask模式,這種模式的Activity只能單獨(dú)位于一個任務(wù)棧內(nèi),由于棧內(nèi)復(fù)用的特性,后續(xù)請求均不會創(chuàng)建新的Activity,除非這個獨(dú)特的任務(wù)棧被系統(tǒng)銷毀了。
Activity的堆棧管理以ActivityRecord為單位,所有的ActivityRecord都放在一個List里面,可以認(rèn)為一個ActivityRecord就是一個Activity棧。
2.使用 Intent 標(biāo)志
在要啟動activity時(shí),你可以在傳給startActivity()的intent中包含相應(yīng)標(biāo)志,以修改activity與task的默認(rèn)關(guān)系。
代碼如下:
Intent i = new Intent(this,NewActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(i);```
還可以通過標(biāo)志修改默認(rèn)模式,如下所示:
* **FLAG_ACTIVITY_NEW_TASK**
與“singleTask”模式相同,在新的task中啟動activity。如果要啟動的activity已經(jīng)運(yùn)行于某個task中,則那個task將調(diào)入前臺。
* **FLAG_ACTIVITY_SINGLE_TOP**
與“singleTop”模式相同,如果要啟動的activity位于back stack棧頂,系統(tǒng)不會重新創(chuàng)建目標(biāo)Activity實(shí)例,而是直接復(fù)用Task棧頂?shù)腁ctivity。
* **FLAG_ACTIVITY_CLEAR_TOP**
此種模式在launchMode中沒有對應(yīng)的屬性值。如果要啟動的activity已經(jīng)在當(dāng)前task中運(yùn)行,則不再啟動一個嶄新的實(shí)例,且所有在其上面的activity將被銷毀。
**關(guān)于啟動模式的一些建議:**
一般不要改變activity和task默認(rèn)的工作方式。如果你確定有必要修改默認(rèn)方式時(shí),請保持謹(jǐn)慎,并確保activity在啟動和從其他activity返回時(shí)的可用性,多做測試和安全方面的工作。
#####Activity緩存方法:
**情景再現(xiàn):**有a,b兩個Activity,當(dāng)從a進(jìn)入b之后一段時(shí)間,可能系統(tǒng)會把a(bǔ)回收,這時(shí)候按back鍵,執(zhí)行的不是a的onRestart(),而是onCreate()方法,a被重新創(chuàng)建一次,這時(shí)a種的臨時(shí)數(shù)據(jù)和狀態(tài)可能丟失了。
**解決辦法:**可以用Activity的 onSaveInstanceState()回調(diào)方法保存臨時(shí)的數(shù)據(jù)和狀態(tài),這個方法一定會在活動被回收之前調(diào)用。方法中有一個Bundle參數(shù),putString(),putInt()等方法需要傳入兩個參數(shù),一個鍵一個值。數(shù)據(jù)保存之后會在onCreate()中恢復(fù),onCreate也有一個Bundle類型的參數(shù)。
**實(shí)例代碼:**
```@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//這里,當(dāng)Acivity第一次被創(chuàng)建的時(shí)候?yàn)榭? //所以我們需要判斷一下
if( savedInstanceState != null ){
savedInstanceState.getString("anAnt");
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("anAnt","Android");
}```
* **onSaveInstanceState(Bundle outState)**
當(dāng)某個activity變得“容易”被系統(tǒng)銷毀時(shí),該activity的onSaveInstanceState就會被執(zhí)行,除非該activity是被用戶主動銷毀的,例如當(dāng)用戶按Back鍵的時(shí)候。
注意上面的雙引號,何為“容易”?言下之意就是該activity還沒有被銷毀,而僅僅是一種可能性。這種可能性有哪些呢?下面,我們通過重新一個activity的所有的生命周期的onXxx()方法,包括onSaveInstanceState()和onRestoreInstanceSatae()方法,我們可以清楚地知道,當(dāng)某個activity(假定為activity A)顯示在當(dāng)前task的最上層時(shí),其onSaveInstanceState()方法會在什么時(shí)候被執(zhí)行,有這么幾種情況:
**1.當(dāng)用戶按下Home鍵時(shí)。**
這中情況是用戶顯而易見的操作,系統(tǒng)不知道你按下Home鍵后要運(yùn)行多少其他的程序,自然也不知道activity A是否會被銷毀,故系統(tǒng)會調(diào)用onSaveInstanceState(),讓用戶有機(jī)會保存某些非永久性的數(shù)據(jù)。以下的幾種情況得分析都遵循該原則。
**2.長按Home鍵,選擇運(yùn)行其他的程序時(shí)。**
**3.按下電源鍵(關(guān)閉屏幕顯示)時(shí)。**
**4.從activity A中啟動一個新的activity時(shí)。**
**5.屏幕方向切換時(shí),例如從豎屏切換到橫屏?xí)r。**(如果不指定configchange屬性)在屏幕切換之前,系統(tǒng)會銷毀activity A,在屏幕切換之后系統(tǒng)又會自動地創(chuàng)建activity A,所以onSaveInstanceState()一定會被執(zhí)行。
**總而言之,onSaveInstanceState()的調(diào)用遵循一個重要原則**,即當(dāng)系統(tǒng)“未經(jīng)過許可”時(shí)銷毀了你的activity,則onSaveInstanceState()會被系統(tǒng)調(diào)用,這是系統(tǒng)的責(zé)任。因?yàn)樗仨氁峁┮粋€機(jī)會讓你保存你的數(shù)據(jù)(當(dāng)然你不保存那就隨你了)。
**另外,需要注意一下幾點(diǎn):**
**<注意點(diǎn) 1>:**布局中的每一個View默認(rèn)實(shí)現(xiàn)了onSaveInstanceState()方法,這樣的話,這個UI的任何改變都會自動地存儲和在activity重新創(chuàng)建的時(shí)候自動地恢復(fù)。但是這種情況只有在你的這個UI提供唯一的ID之后才起作用,如果沒有提供ID,app將不會存儲它的狀態(tài)。
**<注意點(diǎn) 2>:**由于默認(rèn)的onSaveInstanceState()方法的實(shí)現(xiàn)幫助UI存儲它的狀態(tài),所以如果你需要覆蓋這個方法去存儲額外的轉(zhuǎn)態(tài)信息,你應(yīng)該在執(zhí)行任何代碼之前都調(diào)用父類的onSaveInstanceState()方法(super.onSaveInstanceState())。既然有現(xiàn)成的可用,那么我們到底還要不要自己實(shí)現(xiàn)onSaveInstanceState()?這就得看情況了,如果你自己的派生類中有變量影響到UI,或影響到你的程序的行為,當(dāng)然就要把這個變量也保存了,那么就需要自己去實(shí)現(xiàn)了,否則就不需要了。
**<注意點(diǎn) 3>:**由于onSaveInstanceState()方法調(diào)用的不正確性,你應(yīng)該子使用這個方法去記錄activity的瞬間狀態(tài)(UI狀態(tài))。不應(yīng)該用這個方法去存儲持久化數(shù)據(jù)。當(dāng)用戶離開這個activity的時(shí)候應(yīng)該在onPause()方法中存儲持久化數(shù)據(jù)(例如應(yīng)該被存儲到數(shù)據(jù)庫中的數(shù)據(jù))。
**<注意點(diǎn) 4>:**onSaveInsatnceState()如果被調(diào)用,這個方法會在onStop()前被觸發(fā),但是系統(tǒng)并不保證是否在onPause()之前或者之后觸發(fā)。
* **onRestoreInstanceState(Bundle outState)**
至于onRestoreInstanceState()方法,需要注意的是,**onSaveInstanceState()方法和onRestoreInstanceState()方法“不一定”是成對被調(diào)用的。(通過代碼實(shí)踐得到的結(jié)論,并不一定會兩個方法成對被調(diào)用)**
**onRestoreInstanceState()被調(diào)用的前提是**:activity A“確實(shí)”被系統(tǒng)銷毀了,而如果僅僅是停留在有這種可能性的情況下,則該方法不會被調(diào)用,例如,當(dāng)正在顯示的activity A的時(shí)候,用戶按下Home鍵回到主界面,然后用戶緊接著又返回到activty A,這種情況下activity A一般不會因?yàn)閮?nèi)存的原因被系統(tǒng)銷毀,故activity A的onRestoreInstanceState()方法不會被執(zhí)行。
**另外,onRestoreInstanceState()方法的bundle參數(shù)也會傳遞到onCreate()方法中**,你也可以選擇在onCreate()方法中做數(shù)據(jù)的還原。還有onRestoreInstanceState()在onStart()方法之后執(zhí)行。至于這兩個函數(shù)的使用,給出示范代碼(注:要特別留意自定義代碼在調(diào)用super的前或后):
@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
savedInstanceState.putBoolean("MyBoolean", true);
savedInstanceState.putDouble("myDouble", 1.9);
savedInstanceState.putInt("MyInt", 1);
savedInstanceState.putString("MyString", "Welcome back to Android");
// etc.在super() 前 些自己的自定義的代碼
super.onSaveInstanceState(savedInstanceState);
}
@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
// etc.在super() 后 些自己的自定義的代碼
boolean myBoolean = savedInstanceState.getBoolean("MyBoolean");
double myDouble = savedInstanceState.getDouble("myDouble");
int myInt = savedInstanceState.getInt("MyInt");
String myString = savedInstanceState.getString("MyString");
}
#####Fragment的生命周期和Activity之間的關(guān)系:
先上一張F(tuán)ragment和Activity生命周期綜合圖:

* **為什么程序要在Service中創(chuàng)建子線程,而不是Activity中創(chuàng)建呢?**
這是因?yàn)锳ctivty很難對Thread進(jìn)行控制,當(dāng)Activity被銷毀之后,就沒有任何其他的辦法可以再重新獲取到之前創(chuàng)建的子線程的實(shí)例。而且在一個Activity中創(chuàng)建的子線程,在另一個Activity中是無法對其進(jìn)行操作的。但是Service就不同了,所有的Activity都可以與Service進(jìn)行關(guān)聯(lián),然后可以很方便地操作其中的方法,即使Activity被銷毀了,之后只要重新與Service建立關(guān)聯(lián),就又能夠獲取到原有的Service中的Binder的實(shí)例了。因此,使用Service來處理后臺任務(wù),Activity就可以放心的finish(),完全不需要擔(dān)心無法對后臺任務(wù)進(jìn)行控制的情況了。
* **Intent的使用方法,可以傳遞哪些數(shù)據(jù)類型。**
通過查詢Intent/Bundle的API文檔,我們可以獲知,Intent/Bundle支持傳遞基本類型的數(shù)據(jù)和基本類型的數(shù)組數(shù)據(jù),以及String/CharSequence類型的數(shù)據(jù)和String/CharSequence類型的數(shù)組數(shù)據(jù)。而對于其它類型的數(shù)據(jù)貌似無能為力,其實(shí)不然,我們可以在Intent/Bundle的API中看到Intent/Bundle還可以傳遞Parceable(包裹化,郵包)和Serializable(序列化)類型的數(shù)據(jù),以及它們的數(shù)據(jù)/列表數(shù)據(jù)。
所以要讓非基本類型的和非String/CharSequence類型的數(shù)據(jù)通過Intent/Bundle來進(jìn)行傳輸,我們需要在數(shù)據(jù)類型中實(shí)現(xiàn)Parceable接口或是實(shí)現(xiàn)Serializable接口。
[http://blog.csdn.net/kkk0526/article/details/7214247](http://blog.csdn.net/kkk0526/article/details/7214247)
#####解析Intent Filter:
android的3個核心組件---Activity,Services,Braodcast Receiver---是通過Intent傳遞消息的。Intent消息用于在運(yùn)行時(shí)綁定不同的組件。在Android的AndroidMainfest.xml配置文件中可以通過intent-filter節(jié)點(diǎn)為一個Activity指定其Intent Filter,以便于告訴該Activity可以響應(yīng)什么類型的Intent。
* intent-filter的三大屬性:
**Action :**一個Intent Filter可以包含多個Action,Action列表用于標(biāo)志Activity所能接受的“動作”,它是一個用戶自定義的字符串。
<intent-filter >
<action android:name="android.intent.action.MAIN" />
<action android:name="com.wang.app" />
……
</intent-filter>```
也可以在代碼中使用以下語句便可以啟動該Intent對象:
Intent i=new Intent();
i.setAction("com.wang.app");```
Action列表中包含了"com.wang.app"的Activity都將會匹配成功。
**URL :**在inter-filter節(jié)點(diǎn)中,通過data節(jié)點(diǎn)匹配外部數(shù)據(jù),也就是通過URL攜帶外部數(shù)據(jù)給目標(biāo)組件。
<data android:mimeType="mimeType"
android:scheme="scheme"
android:host="host"
android:port="port"
android:path="path"/>```
注意:只有data的所有的屬性都匹配成功時(shí),URL數(shù)據(jù)匹配才會成功。
Category :為組件定義一個類別列表,當(dāng)Intent中包含這個類別列表的所有項(xiàng)目時(shí),才會匹配成功。
<intent-filter . . . >
<action android:name="code.android.intent.action.MAIN" />
<category android:name="code.android.intent.category.LAUNCHER" />
</intent-filter>```
**Activity中Intent Filter的匹配過程:**
(1)加載所有的Intent Filter列表
(2)去掉action匹配失敗的Intent Filter
(3)去掉url匹配失敗的Intent Filter
(4)去掉Category匹配失敗的Intent Filter
(5)判斷剩下的Intent Filter數(shù)目是否為0,如果為0查找失敗返回異常;如果大于0,就按優(yōu)先級排序,返回最高優(yōu)先級的Intent Filter。
#####開發(fā)中Activity的一些問題:
一般設(shè)置Activity為非公開的
<activity
......
android:exported="false" /> ```
注意:非公開的Activity不能設(shè)置intent-filter,以免被其他的activity喚醒(如果擁有相同的intent-filter)。
- 不要指定activity的taskAffinity屬性。
- 不要設(shè)置activity的LaunchMode(保持默認(rèn)),注意Activity的intent最好也不要設(shè)定為FLAG_ACTIVITY_NEW_TASK
- 在匿名內(nèi)部類中使用this時(shí),加上activity類名(類名.this,不一定是當(dāng)前的activity)
- 設(shè)置activity全屏:在其onCreate()方法中加入代碼:
// 設(shè)置全屏模式
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
// 去除標(biāo)題欄
requestWindowFeature(Window.FEATURE_NO_TITLE);```
**結(jié)束語:我害怕,自己在最該努力的時(shí)光中,卻選擇了安逸。 ---王令
QQ:2585085940
郵箱:wang91ling@163.com
歡迎大家光臨寒舍。**