Android四大基本組件介紹與生命周期

轉(zhuǎn)自Android四大基本組件介紹與生命周期
Android四大基本組件分別是Activity,Service服務(wù),Content Provider內(nèi)容提供者姨谷,BroadcastReceiver廣播接收器。
一:了解四大基本組件
Activity :
應(yīng)用程序中节腐,一個Activity通常就是一個單獨的屏幕燕差,它上面可以顯示一些控件也可以監(jiān)聽并處理用戶的事件做出響應(yīng)捂襟。
Activity之間通過Intent進(jìn)行通信。在Intent 的描述結(jié)構(gòu)中趴酣,有兩個最重要的部分:動作和動作對應(yīng)的數(shù)據(jù)梨树。
典型的動作類型有:M AIN(activity的門戶)、VIEW岖寞、PICK抡四、EDIT 等。而動作對應(yīng)的數(shù)據(jù)則以URI 的形式進(jìn)行表示慎璧。例如:要查看一個人的聯(lián)系方式床嫌,你需要創(chuàng)建一個動作類型為VIEW 的intent,以及一個表示這個人的URI胸私。
與之有關(guān)系的一個類叫IntentFilter。相對于intent 是一個有效的做某事的請求鳖谈,一個intentfilter 則用于描述一個activity(或者IntentReceiver)能夠操作哪些intent岁疼。一個activity 如果要顯示一個人的聯(lián)系方式時,需要聲明一個IntentFilter缆娃,這個IntentFilter 要知道怎么去處理VIEW 動作和表示一個人的URI捷绒。IntentFilter 需要在AndroidManifest.xml 中定義。通過解析各種intent贯要,從一個屏幕導(dǎo)航到另一個屏幕是很簡單的暖侨。當(dāng)向前導(dǎo)航時,activity 將會調(diào)用startActivity(Intent myIntent)方法崇渗。然后字逗,系統(tǒng)會在所有安裝的應(yīng)用程序中定義的IntentFilter 中查找,找到最匹配myIntent 的Intent 對應(yīng)的activity宅广。新的activity 接收到myIntent 的通知后葫掉,開始運行末盔。當(dāng)startActivity 方法被調(diào)用將觸發(fā)解析myIntent 的動作修陡,這個機(jī)制提供了兩個關(guān)鍵好處:
A宙攻、Activities 能夠重復(fù)利用從其它組件中以Intent 的形式產(chǎn)生的一個請求拍顷;
B谜慌、Activities 可以在任何時候被一個具有相同IntentFilter 的新的Activity 取代籽暇。
AndroidManifest文件中含有如下過濾器的Activity組件為默認(rèn)啟動類當(dāng)程序啟動時系統(tǒng)自動調(diào)用它

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

BroadcastReceive****廣播接收器:
你的應(yīng)用可以使用它對外部事件進(jìn)行過濾只對感興趣的外部事件(如當(dāng)電話呼入時洞拨,或者數(shù)據(jù)網(wǎng)絡(luò)可用時)進(jìn)行接收并做出響應(yīng)罢浇。廣播接收器沒有用戶界面关翎。然而扛门,它們可以啟動一個activity或serice 來響應(yīng)它們收到的信息,或者用NotificationManager 來通知用戶笤休。通知可以用很多種方式來吸引用戶的注意力──閃動背燈尖飞、震動、播放聲音等。一般來說是在狀態(tài)欄上放一個持久的圖標(biāo)政基,用戶可以打開它并獲取消息贞铣。
廣播類型:
普通廣播通過Context.sendBroadcast(Intent myIntent)發(fā)送的
有序廣播沮明,通過Context.sendOrderedBroadcast(intent, receiverPermission)發(fā)送的辕坝,該方法第2個參數(shù)決定該廣播的級別,級別數(shù)值是在 -1000 到 1000 之間 , 值越大 , 發(fā)送的優(yōu)先級越高荐健;廣播接收者接收廣播時的級別級別(可通過intentfilter中的priority進(jìn)行設(shè)置設(shè)為2147483647時優(yōu)先級最高)酱畅,同級別接收的先后是隨機(jī)的, 再到級別低的收到廣播江场,高級別的或同級別先接收到廣播的可以通過abortBroadcast()方法截斷廣播使其他的接收者無法收到該廣播纺酸,還有其他構(gòu)造函數(shù)
異步廣播通過Context.sendStickyBroadcast(Intent myIntent)發(fā)送的址否,還有sendStickyOrderedBroadcast(intent, resultReceiver, scheduler, initialCode, initialData, initialExtras)方法餐蔬,該方法具有有序廣播的特性也有異步廣播的特性;發(fā)送異步廣播要: <uses-permission android:name="android.permission.BROADCAST_STICKY" />權(quán)限佑附,接收并處理完Intent后樊诺,廣播依然存在,直到你調(diào)用removeStickyBroadcast(intent)主動把它去掉
注意:發(fā)送廣播時的intent參數(shù)與Contex.startActivity()啟動起來的Intent不同,前者可以被多個訂閱它的廣播接收器調(diào)用,后者只能被一個(Activity或service)調(diào)用
監(jiān)聽廣播Intent步驟:
1> 寫一個繼承BroadCastReceiver的類,重寫onReceive()方法,廣播接收器僅在它執(zhí)行這個方法時處于活躍狀態(tài)音同。當(dāng)onReceive()返回后词爬,它即為失活狀態(tài),注意:為了保證用戶交互過程的流暢,一些費時的操作要放到線程里,如類名SMSBroadcastReceiver
2> 注冊該廣播接收者,注冊有兩種方法程序動態(tài)注冊和AndroidManifest文件中進(jìn)行靜態(tài)注冊(可理解為系統(tǒng)中注冊)如下:
靜態(tài)注冊,注冊的廣播,下面的priority表示接收廣播的級別"2147483647"為最高優(yōu)先級
<receiver android:name=".SMSBroadcastReceiver" >  <intent-filter android:priority = "2147483647" >    <action android:name="android.provider.Telephony.SMS_RECEIVED" />  </intent-filter></receiver >

動態(tài)注冊权均,一般在Activity可交互時onResume()內(nèi)注冊BroadcastReceiver
IntentFilter intentFilter=new IntentFilter("android.provider.Telephony.SMS_RECEIVED");registerReceiver(mBatteryInfoReceiver ,intentFilter);//反注冊unregisterReceiver(receiver);

注意:
1.生命周期只有十秒左右顿膨,如果在 onReceive() 內(nèi)做超過十秒內(nèi)的事情,就會報ANR(Application No Response) 程序無響應(yīng)的錯誤信息螺句,如果需要完成一項比較耗時的工作 , 應(yīng)該通過發(fā)送 Intent 給 Service, 由Service 來完成 . 這里不能使用子線程來解決 , 因為 BroadcastReceiver 的生命周期很短 , 子線程可能還沒有結(jié)束BroadcastReceiver 就先結(jié)束了 .BroadcastReceiver 一旦結(jié)束 , 此時 BroadcastReceiver 的所在進(jìn)程很容易在系統(tǒng)需要內(nèi)存時被優(yōu)先殺死 , 因為它屬于空進(jìn)程 ( 沒有任何活動組件的進(jìn)程 ). 如果它的宿主進(jìn)程被殺死 , 那么正在工作的子線程也會被殺死 . 所以采用子線程來解決是不可靠的

  1. 動態(tài)注冊廣播接收器還有一個特點虽惭,就是當(dāng)用來注冊的Activity關(guān)掉后,廣播也就失效了蛇尚。靜態(tài)注冊無需擔(dān)憂廣播接收器是否被關(guān)閉,只要設(shè)備是開啟狀態(tài),廣播接收器也是打開著的芽唇。也就是說哪怕app本身未啟動,該app訂閱的廣播在觸發(fā)時也會對它起作用
    系統(tǒng)常見廣播Intent,如開機(jī)啟動、電池電量變化取劫、時間改變等廣播
    Service ****服務(wù):
    一個Service 是一段長生命周期的匆笤,沒有用戶界面的程序,可以用來開發(fā)如監(jiān)控類程序谱邪。
    比較好的一個例子就是一個正在從播放列表中播放歌曲的媒體播放器炮捧。在一個媒體播放器的應(yīng)用中,應(yīng)該會有多個activity惦银,讓使用者可以選擇歌曲并播放歌曲咆课。然而末誓,音樂重放這個功能并沒有對應(yīng)的activity,因為使用者當(dāng)然會認(rèn)為在導(dǎo)航到其它屏幕時音樂應(yīng)該還在播放的书蚪。在這個例子中喇澡,媒體播放器這個activity 會使用Context.startService()來啟動一個service,從而可以在后臺保持音樂的播放殊校。同時晴玖,系統(tǒng)也將保持這個service 一直執(zhí)行,直到這個service 運行結(jié)束为流。另外呕屎,我們還可以通過使用Context.bindService()方法,連接到一個service 上(如果這個service 還沒有運行將啟動它)敬察。當(dāng)連接到一個service 之后秀睛,我們還可以service 提供的接口與它進(jìn)行通訊。拿媒體播放器這個例子來說莲祸,我們還可以進(jìn)行暫停琅催、重播等操作。
    Service使用步驟如下
    1>繼承service類
    2>AndroidManifast.xml配置清單文件中<application>節(jié)點里對服務(wù)進(jìn)行配置
    <service name=".SMSService"/>
    服務(wù)不能自己運行,需要通過Contex.startService()或Contex.bindService()啟動服務(wù)
    通過startService()方法啟動的服務(wù)于調(diào)用者沒有關(guān)系,即使調(diào)用者關(guān)閉了,服務(wù)仍然運行想停止服務(wù)要調(diào)用Context.stopService(),此時系統(tǒng)會調(diào)用onDestory(),使用此方法啟動時,服務(wù)首次啟動系統(tǒng)先調(diào)用服務(wù)的onCreate()-->onStart(),如果服務(wù)已經(jīng)啟動再次調(diào)用只會觸發(fā)onStart()方法
    使用bindService()啟動的服務(wù)與調(diào)用者綁定,只要調(diào)用者關(guān)閉服務(wù)就終止,使用此方法啟動時,服務(wù)首次啟動系統(tǒng)先調(diào)用服務(wù)的onCreate()-->onBind(),如果服務(wù)已經(jīng)啟動再次調(diào)用不會再觸發(fā)這2個方法,調(diào)用者退出時系統(tǒng)會調(diào)用服務(wù)的onUnbind()-->onDestory(),想主動解除綁定可使用Contex.unbindService(),系統(tǒng)依次調(diào)用onUnbind()-->onDestory();
    Content Provider****內(nèi)容提供者 :
    android平臺提供了Content Provider使一個應(yīng)用程序的指定數(shù)據(jù)集提供給其他應(yīng)用程序虫给。這些數(shù)據(jù)可以存儲在文件系統(tǒng)中、在一個SQLite數(shù)據(jù)庫侠碧、或以任何其他合理的方式,
    其他應(yīng)用可以通過ContentResolver類(見ContentProviderAccessApp例子)從該內(nèi)容提供者中獲取或存入數(shù)據(jù).(相當(dāng)于在應(yīng)用外包了一層殼),
    只有需要在多個應(yīng)用程序間共享數(shù)據(jù)是才需要內(nèi)容提供者抹估。例如,通訊錄數(shù)據(jù)被多個應(yīng)用程序使用弄兜,且必須存儲在一個內(nèi)容提供者中
    它的好處:統(tǒng)一數(shù)據(jù)訪問方式药蜻。
    android系統(tǒng)自帶的內(nèi)容提供者(頂級的表示數(shù)據(jù)庫名,非頂級的都是表名)這些內(nèi)容提供者在SDK文檔的android.provider Java包中都有介紹。見:http://developer.android.com/reference/android/provider/package-summary.html
    ├────Browser
    ├────CallLog
    ├────Contacts
    │ ├────Groups
    │ ├────People
    │ ├────Phones
    │ └────Photos
    ├────Images
    │ └────Thumbnails
    ├────MediaStore
    │ ├────Albums
    │ ├────Artists
    │ ├────Audio
    │ ├────Genres
    │ └────Playlists
    ├────Settings
    └────Video
    CallLog:地址和接收到的電話信息
    Contact.People.Phones:存儲電話號碼
    Setting.System:系統(tǒng)設(shè)置和偏好設(shè)置
    使用Content Provider對外共享數(shù)據(jù)的步驟
    1>繼承ContentProvider類并根據(jù)需求重寫以下方法:

復(fù)制代碼

    public boolean onCreate();//處理初始化操作 /** * 插入數(shù)據(jù)到內(nèi)容提供者(允許其他應(yīng)用向你的應(yīng)用中插入數(shù)據(jù)時重寫) * @param uri * @param initialValues 插入的數(shù)據(jù) * @return / public Uri insert(Uri uri, ContentValues initialValues); /* * 從內(nèi)容提供者中刪除數(shù)據(jù)(允許其他應(yīng)用刪除你應(yīng)用的數(shù)據(jù)時重寫) * @param uri * @param selection 條件語句 * @param selectionArgs 參數(shù) * @return / public int delete(Uri uri, String selection, String[] selectionArgs); /* * 更新內(nèi)容提供者已存在的數(shù)據(jù)(允許其他應(yīng)用更新你應(yīng)用的數(shù)據(jù)時重寫) * @param uri * @param values 更新的數(shù)據(jù) * @param selection 條件語句 * @param selectionArgs 參數(shù) * @return / public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs); /* * 返回數(shù)據(jù)給調(diào)用者(允許其他應(yīng)用從你的應(yīng)用中獲取數(shù)據(jù)時重寫) * @param uri * @param projection 列名 * @param selection 條件語句 * @param selectionArgs 參數(shù) * @param sortOrder 排序 * @return / public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) ; /* * 用于返回當(dāng)前Uri所代表數(shù)據(jù)的MIME類型 * 如果操作的數(shù)據(jù)為集合類型(多條數(shù)據(jù)),那么返回的類型字符串應(yīng)該為vnd.android.cursor.dir/開頭 * 例如要得到所有person記錄的Uri為content://com.bravestarr.provider.personprovider/person,     *   那么返回的MIME類型字符串應(yīng)該為"vnd.android.cursor.dir/person" * 如果操作的數(shù)據(jù)為單一數(shù)據(jù),那么返回的類型字符串應(yīng)該為vnd.android.cursor.item/開頭 * 例如要得到id為10的person記錄的Uri為content://com.bravestarr.provider.personprovider/person/10,     *   那么返回的MIME類型字符串應(yīng)該為"vnd.android.cursor.item/person" * @param uri */ public String getType(Uri uri)
復(fù)制代碼

這些方法中的Uri參數(shù),得到后需要進(jìn)行解析然后做對應(yīng)處理,Uri表示要操作的數(shù)據(jù),包含兩部分信息:
1.需要操作的contentprovider
2.對contentprovider中的什么數(shù)據(jù)進(jìn)行操作,一個Uri格式:結(jié)構(gòu)頭://authorities(域名)/路徑(要操作的數(shù)據(jù),根據(jù)業(yè)務(wù)而定)
content://com.bravestarr.provider.personprovider/person/10
說明:contentprovider的結(jié)構(gòu)頭已經(jīng)由android規(guī)定為content://
authorities用于唯一標(biāo)識這個contentprovider程序,外部調(diào)用者可以根據(jù)這個找到他
路徑表示我們要操作的數(shù)據(jù),路徑的構(gòu)建根據(jù)業(yè)務(wù)而定.路徑格式如下:
要操作person表行號為10的記錄,可以這樣構(gòu)建/person/10
要操作person表的所有記錄,可以這樣構(gòu)建/person
2>在AndroidManifest.xml中使用<provider>對ContentProvider進(jìn)行配置注冊(內(nèi)容提供者注冊它自己就像網(wǎng)站注冊域名),ContentProvider采用authoritie(原意授權(quán),可理解為域名)作為唯一標(biāo)識,方便其他應(yīng)用能找到

復(fù)制代碼

<application android:icon="@drawable/ic_launcher" android:label="@string/app_name" > <provider android:name=".PersonProvider" android:authorities="com.bravestarr.provider.personprovider"/> ...</application>
復(fù)制代碼

關(guān)于四大基本組件的一個總結(jié):
1> 4大組件的注冊
4大基本組件都需要注冊才能使用,每個Activity替饿、service语泽、Content Provider內(nèi)容提供者都需要在AndroidManifest文件中進(jìn)行配置AndroidManifest文件中未進(jìn)行聲明的activity、服務(wù)以及內(nèi)容提供者將不為系統(tǒng)所見视卢,從而也就不可用踱卵,而BroadcastReceive廣播接收者的注冊分靜態(tài)注冊(在AndroidManifest文件中進(jìn)行配置)和通過代碼動態(tài)創(chuàng)建并以調(diào)用Context.registerReceiver()的方式注冊至系統(tǒng)。需要注意的是在AndroidManifest文件中進(jìn)行配置的廣播接收者會隨系統(tǒng)的啟動而一直處于活躍狀態(tài),只要接收到感興趣的廣播就會觸發(fā)(即使程序未運行)
AndroidManifest文件中進(jìn)行注冊格式如下:
<activity>元素的name 屬性指定了實現(xiàn)了這個activity 的Activity 的子類据过。icon 和label 屬性指向了包含展示給用戶的此activity 的圖標(biāo)和標(biāo)簽的資源文件惋砂。
<service> 元素用于聲明服務(wù)
<receiver> 元素用于聲明廣播接收器
<provider> 元素用于聲明內(nèi)容提供者
2> 4大組件的激活
? 容提供者的激活:當(dāng)接收到ContentResolver 發(fā)出的請求后,內(nèi)容提供者被激活绳锅。而其它三種組件──activity西饵、服務(wù)和廣播接收器被一種叫做intent 的異步消息所激活
? Activity的激活通過傳遞一個Intent 對象至Context.startActivity()或Activity.startActivityForResult()以載入(或指定新工作給)一個activity。相應(yīng)的activity 可以通過調(diào)用getIntent() 方法來查看激活它的intent鳞芙。如果它期望它所啟動的那個activity 返回一個結(jié)果眷柔,它會以調(diào)用startActivityForResult()來取代startActivity()期虾。比如說,如果它啟動了另外一個Activity 以使用戶挑選一張照片驯嘱,它也許想知道哪張照片被選中了镶苞。結(jié)果將會被封裝在一個Intent 對象中,并傳遞給發(fā)出調(diào)用的activity 的onActivityResult() 方法宙拉。
? 服務(wù)的激活可以通過傳遞一個Intent 對象至Context.startService()或Context.bindService()前者Android 調(diào)用服務(wù)的onStart()方法并將Intent 對象傳遞給它宾尚,后者Android 調(diào)用服務(wù)的onBind()方法將這個Intent 對象傳遞給它
? 發(fā)送廣播可以通過傳遞一個Intent 對象至給Context.sendBroadcast() 、
Context.sendOrderedBroadcast()或Context.sendStickyBroadcast()Android 會調(diào)用所有對此廣播有興趣的廣播接收器的onReceive()方法谢澈,將intent 傳遞給它們
3> 四大組件的關(guān)閉
內(nèi)容提供者僅在響應(yīng)ContentResolver 提出請求的時候激活煌贴。而一個廣播接收器僅在響應(yīng)廣播信息的時候激活。所以锥忿,沒有必要去顯式的關(guān)閉這些組件牛郑。
Activity關(guān)閉:可以通過調(diào)用它的finish()方法來關(guān)閉一個activity
服務(wù)關(guān)閉:對于通過startService()方法啟動的服務(wù)要調(diào)用Context.stopService()方法關(guān)閉服務(wù),使用bindService()方法啟動的服務(wù)要調(diào)用Contex.unbindService ()方法關(guān)閉服務(wù)
二:四大組件的生命周期
介紹生命周期之前敬鬓,先提一下任務(wù)的概念
任務(wù)其實就是activity 的棧它由一個或多個Activity組成的共同完成一個完整的用戶體驗淹朋, 換句話說任務(wù)就是” 應(yīng)用程序” (可以是一個也可以是多個,比如假設(shè)你想讓用戶看到某個地方的街道地圖钉答。而已經(jīng)存在一個具有此功能的activity 了础芍,那么你的activity 所需要做的工作就是把請求信息放到一個Intent 對象里面,并把它傳遞給startActivity()数尿。于是地圖瀏覽器就會顯示那個地圖仑性。而當(dāng)用戶按下BACK 鍵的時候,你的activity 又會再一次的顯示在屏幕上右蹦,此時任務(wù)是由2個應(yīng)用程序中的相關(guān)activity組成的)棧底的是啟動整個任務(wù)的Activity诊杆,棧頂?shù)氖钱?dāng)前運行的用戶可以交互的Activity,當(dāng)一個activity 啟動另外一個的時候何陆,新的activity 就被壓入棧晨汹,并成為當(dāng)前運行的activity。而前一個activity 仍保持在棧之中贷盲。當(dāng)用戶按下BACK 鍵的時候淘这,當(dāng)前activity 出棧,而前一個恢復(fù)為當(dāng)前運行的activity晃洒。棧中保存的其實是對象慨灭,棧中的Activity 永遠(yuǎn)不會重排,只會壓入或彈出球及,所以如果發(fā)生了諸如需要多個地圖瀏覽器的情況氧骤,就會使得一個任務(wù)中出現(xiàn)多個同一Activity 子類的實例同時存在。
任務(wù)中的所有activity 是作為一個整體進(jìn)行移動的吃引。整個的任務(wù)(即activity 棧)可以移到前臺筹陵,或退至后臺刽锤。舉個例子說,比如當(dāng)前任務(wù)在棧中存有四個activity──三個在當(dāng)前activity 之下朦佩。當(dāng)用戶按下HOME 鍵的時候并思,回到了應(yīng)用程序加載器,然后選擇了一個新的應(yīng)用程序(也就是一個新任務(wù))语稠。則當(dāng)前任務(wù)遁入后臺宋彼,而新任務(wù)的根activity 顯示出來。然后仙畦,過了一小會兒输涕,用戶再次回到了應(yīng)用程序加載器而又選擇了前一個應(yīng)用程序(上一個任務(wù))。于是那個任務(wù)慨畸,帶著它棧中所有的四個activity莱坎,再一次的到了前臺。當(dāng)用戶按下BACK 鍵的時候寸士,屏幕不會顯示出用戶剛才離開的activity(上一個任務(wù)的根
activity)檐什。取而代之,當(dāng)前任務(wù)的棧中最上面的activity 被彈出弱卡,而同一任務(wù)中的上一個activity 顯示了出來乃正。
Activity棧:先進(jìn)后出規(guī)則



Android系統(tǒng)是一個多任務(wù)(Multi-Task)的操作系統(tǒng),可以在用手機(jī)聽音樂的同時婶博,也執(zhí)行其他多個程序烫葬。每多執(zhí)行一個應(yīng)用程序,就會多耗費一些系統(tǒng)內(nèi)存凡蜻,當(dāng)同時執(zhí)行的程序過多,或是關(guān)閉的程序沒有正確釋放掉內(nèi)存垢箕,系統(tǒng)就會覺得越來越慢划栓,甚至不穩(wěn)定。
為了解決這個問題条获, Android 引入了一個新的機(jī)制-- 生命周期(Life Cycle)忠荞。
Android 應(yīng)用程序的生命周期是由Android 框架進(jìn)行管理,而不是由應(yīng)用程序直接控
制帅掘。通常委煤,每一個應(yīng)用程序(入口一般會是一個Activity 的onCreate 方法),都會產(chǎn)生
一個進(jìn)程(Process)修档。當(dāng)系統(tǒng)內(nèi)存即將不足的時候碧绞,會依照優(yōu)先級自動進(jìn)行進(jìn)程(process)的回收。不管是使用者或開發(fā)者吱窝, 都無法確定的應(yīng)用程序何時會被回收讥邻。所以為了很好的防止數(shù)據(jù)丟失和其他問題迫靖,了解生命周期很重要。
Activity生命周期:



圖3.1activity生命周期圖
Activity整個生命周期的4種狀態(tài)兴使、7個重要方法和3個嵌套循環(huán)
1> 四種狀態(tài)
活動(Active/Running)狀態(tài)

當(dāng)Activity運行在屏幕前臺(處于當(dāng)前任務(wù)活動棧的最上面),此時它獲取了焦點能響應(yīng)用戶的操作,屬于運行狀態(tài)系宜,同一個時刻只會有一個Activity 處于活動(Active)或運行
(Running)狀態(tài)
暫停(Paused)狀態(tài)

當(dāng)Activity失去焦點但仍對用戶可見(如在它之上有另一個透明的Activity或Toast、AlertDialog等彈出窗口時)它處于暫停狀態(tài)发魄。暫停的Activity仍然是存活狀態(tài)(它保留著所有的狀態(tài)和成員信息并保持和窗口管理器的連接),但是當(dāng)系統(tǒng)內(nèi)存極小時可以被系統(tǒng)殺掉

  1.  停止(Stopped)狀態(tài)
    

完全被另一個Activity遮擋時處于停止?fàn)顟B(tài),它仍然保留著所有的狀態(tài)和成員信息盹牧。只是對用戶不可見,當(dāng)其他地方需要內(nèi)存時它往往被系統(tǒng)殺掉

  1.  非活動(Dead)狀態(tài)
    

Activity 尚未被啟動、已經(jīng)被手動終止励幼,或已經(jīng)被系統(tǒng)回收時處于非活動的狀態(tài)汰寓,要手動終止Activity,可以在程序中調(diào)用"finish"方法赏淌。
如果是(按根據(jù)內(nèi)存不足時的回收規(guī)則)被系統(tǒng)回收踩寇,可能是因為內(nèi)存不足了
內(nèi)存不足時,Dalvak 虛擬機(jī)會根據(jù)其內(nèi)存回收規(guī)則來回收內(nèi)存:
1. 先回收與其他Activity 或Service/Intent Receiver 無關(guān)的進(jìn)程(即優(yōu)先回收獨
立的Activity)因此建議,我們的一些(耗時)后臺操作六水,最好是作成Service的形式
2.不可見(處于Stopped狀態(tài)的)Activity
3.Service進(jìn)程(除非真的沒有內(nèi)存可用時會被銷毀)
4.非活動的可見的(Paused狀態(tài)的)Activity
5.當(dāng)前正在運行(Active/Running狀態(tài)的)Activity

2> 7個重要方法,當(dāng)Activity從一種狀態(tài)進(jìn)入另一狀態(tài)時系統(tǒng)會自動調(diào)用下面相應(yīng)的方
法來通知用戶這種變化
當(dāng)Activity第一次被實例化的時候系統(tǒng)會調(diào)用,
整個生命周期只調(diào)用1次這個方法
通常用于初始化設(shè)置: 1俺孙、為Activity設(shè)置所要使用的布局文件2、為按鈕綁定監(jiān)聽器等靜態(tài)的設(shè)置操作
onCreate(Bundle savedInstanceState);

當(dāng)Activity可見未獲得用戶焦點不能交互時系統(tǒng)會調(diào)用
onStart();

當(dāng)Activity已經(jīng)停止然后重新被啟動時系統(tǒng)會調(diào)用
onRestart();

當(dāng)Activity可見且獲得用戶焦點能交互時系統(tǒng)會調(diào)用
onResume();

當(dāng)系統(tǒng)啟動另外一個新的Activity時,在新Activity啟動之前被系統(tǒng)調(diào)用保存現(xiàn)有的Activity中的持久數(shù)據(jù)掷贾、停止動畫等,這個實現(xiàn)方法必須非尘﹂快。當(dāng)系統(tǒng)而不是用戶自己出于回收內(nèi)存時想帅,關(guān)閉了activity 之后场靴。用戶會期望當(dāng)他再次回到這個activity 的時候,它仍保持著上次離開時的樣子港准。此時用到了onSaveInstanceState()旨剥,方法onSaveInstanceState()用來保存Activity被殺之前的狀態(tài),在onPause()之前被觸發(fā),當(dāng)系統(tǒng)為了節(jié)省內(nèi)存銷毀了Activity(用戶本不想銷毀)時就需要重寫這個方法了,當(dāng)此Activity再次被實例化時會通過onCreate(Bundle savedInstanceState)將已經(jīng)保存的臨時狀態(tài)數(shù)據(jù)傳入因為onSaveInstanceState()方法不總是被調(diào)用,觸發(fā)條件為(按下HOME鍵,按下電源按鍵關(guān)閉屏幕,橫豎屏切換情況下),你應(yīng)該僅重寫onSaveInstanceState()來記錄activity的臨時狀態(tài),而不是持久的數(shù)據(jù)浅缸。應(yīng)該使用onPause()來存儲持久數(shù)據(jù)轨帜。
onPause();

當(dāng)Activity被新的Activity完全覆蓋不可見時被系統(tǒng)調(diào)用
onStop();

當(dāng)Activity(用戶調(diào)用finish()或系統(tǒng)由于內(nèi)存不足)被系統(tǒng)銷毀殺掉時系統(tǒng)調(diào)用,(整個生命周期只調(diào)用1次)用來釋放onCreate ()方法中創(chuàng)建的資源,如結(jié)束線程等
onDestroy();

3> 3個嵌套循環(huán)
1.Activity完整的生命周期:從第一次調(diào)用onCreate()開始直到調(diào)用onDestroy()結(jié)束
2.Activity的可視生命周期:從調(diào)用onStart()到相應(yīng)的調(diào)用onStop()
在這兩個方法之間,可以保持顯示Activity所需要的資源。如在onStart()中注冊一個廣播接收者監(jiān)聽影響你的UI的改變,在onStop() 中注銷衩椒。
3.Activity的前臺生命周期:從調(diào)用onResume()到相應(yīng)的調(diào)用onPause()蚌父。

  舉例說明:

例1:有3個Acitivity,分別用One,Two(透明的),Three表示,One是應(yīng)用啟動時的主Activity
啟動第一個界面Activity One時,它的次序是
onCreate (ONE) - onStart (ONE) - onResume(ONE)
點"打開透明Activity"按鈕時,這時走的次序是
onPause(ONE) - onCreate(TWO) - onStart(TWO) - onResume(TWO)
再點back回到第一個界面,Two會被殺這時走的次序是
onPause(TWO) - onActivityResult(ONE) - onResume(ONE) - onStop(TWO) - onDestroy(TWO)
點"打開全屏Activity"按鈕時,這時走的次序是
onPause(ONE) - onCreate(Three) - onStart(Three) - onResume(Three) - onStop(ONE)
再點back回到第一個界面,Three會被殺這時走的次序是
onPause(Three) - onActivityResult(ONE) - onRestart(ONE) - onStart(ONE)- onResume(ONE) - onStop(Three) - onDestroy(Three)
再點back退出應(yīng)用時,它的次序是
onPause(ONE) - onStop(ONE) - onDestroy(ONE)

例2:橫豎屏切換時候Activity的生命周期
他切換時具體的生命周期是怎么樣的:
1、新建一個Activity毛萌,并把各個生命周期打印出來
2苟弛、運行Activity,得到如下信息
onCreate-->onStart-->onResume-->
3阁将、按crtl+f12切換成橫屏?xí)r
onSaveInstanceState-->onPause-->onStop-->onDestroy-->onCreate-->onStart-->onRestoreInstanceState-->onResume-->
4膏秫、再按crtl+f12切換成豎屏?xí)r,發(fā)現(xiàn)打印了兩次相同的log
onSaveInstanceState-->onPause-->onStop-->onDestroy-->onCreate-->onStart-->onRestoreInstanceState-->onResume-->onSaveInstanceState-->onPause-->onStop-->onDestroy-->onCreate-->onStart-->onRestoreInstanceState-->onResume-->
5做盅、修改AndroidManifest.xml荔睹,把該Activity添加android:configChanges="orientation"狸演,執(zhí)行步驟3
onSaveInstanceState-->onPause-->onStop-->onDestroy-->onCreate-->onStart-->onRestoreInstanceState-->onResume-->
6、再執(zhí)行步驟4僻他,發(fā)現(xiàn)不會再打印相同信息宵距,但多打印了一行onConfigChanged
onSaveInstanceState-->onPause-->onStop-->onDestroy-->onCreate-->onStart-->onRestoreInstanceState-->onResume-->onConfigurationChanged-->
7、把步驟5的android:configChanges="orientation" 改成 android:configChanges="orientation|keyboardHidden"吨拗,執(zhí)行步驟3满哪,就只打印onConfigChanged
onConfigurationChanged-->
8、執(zhí)行步驟4
onConfigurationChanged-->onConfigurationChanged-->
總結(jié):
1劝篷、不設(shè)置Activity的android:configChanges時哨鸭,切屏?xí)匦抡{(diào)用各個生命周期,切橫屏?xí)r會執(zhí)行一次娇妓,切豎屏?xí)r會執(zhí)行兩次
2像鸡、設(shè)置Activity的android:configChanges="orientation"時,切屏還是會重新調(diào)用各個生命周期哈恰,切橫只估、豎屏?xí)r只會執(zhí)行一次
3、設(shè)置Activity的android:configChanges="orientation|keyboardHidden"時着绷,切屏不會重新調(diào)用各個生命周期蛔钙,只會執(zhí)行onConfigurationChanged方法
總結(jié)一下整個Activity的生命周期
補充一點,當(dāng)前Activity產(chǎn)生事件彈出Toast和AlertDialog的時候Activity的生命周期不會有改變
Activity運行時按下HOME鍵(跟被完全覆蓋是一樣的):onSaveInstanceState --> onPause --> onStop荠医,再次進(jìn)入激活狀態(tài)時: onRestart -->onStart--->onResume
BroadcastReceive廣播接收器生命周期:
生命周期只有十秒左右吁脱,如果在 onReceive() 內(nèi)做超過十秒內(nèi)的事情,就會報ANR(Application No Response) 程序無響應(yīng)的錯誤信息
它的生命周期為從回調(diào)onReceive()方法開始到該方法返回結(jié)果后結(jié)束
Service服務(wù)生命周期:



圖3.2service生命周期圖
Service完整的生命周期:從調(diào)用onCreate()開始直到調(diào)用onDestroy()結(jié)束
Service有兩種使用方法:
1>以調(diào)用Context.startService()啟動彬向,而以調(diào)用Context.stopService()結(jié)束
2>以調(diào)用Context.bindService()方法建立兼贡,以調(diào)用Context.unbindService()關(guān)閉
service重要的生命周期方法
當(dāng)用戶調(diào)用startService ()或bindService()時,Service第一次被實例化的時候系統(tǒng)會調(diào)用,整個生命周期只調(diào)用1次這個方法娃胆,通常用于初始化設(shè)置紧显。注意:多次調(diào)用startService()或bindService()方法不會多次觸發(fā)onCreate()方法
void onCreate()

當(dāng)用戶調(diào)用stopService()或unbindService()來停止服務(wù)時被系統(tǒng)調(diào)用,(整個生命周期只調(diào)用1次)用來釋放onCreate()方法中創(chuàng)建的資源
void onDestroy()

通過startService()方法啟動的服務(wù)
初始化結(jié)束后系統(tǒng)會調(diào)用該方法,用于處理傳遞給startService()的Intent對象缕棵。如音樂服務(wù)會打開Intent 來探明將要播放哪首音樂,并開始播放涉兽。注意:多次調(diào)用startService()方法會多次觸發(fā)onStart()方法
void onStart(Intent intent)

通過bindService ()方法啟動的服務(wù)
初始化結(jié)束后系統(tǒng)會調(diào)用該方法招驴,用來綁定傳遞給bindService 的Intent 的對象。注意:多次調(diào)用bindService()時枷畏,如果該服務(wù)已啟動則不會再觸發(fā)此方法
IBinder onBind(Intent intent)

用戶調(diào)用unbindService()時系統(tǒng)調(diào)用此方法别厘,Intent 對象同樣傳遞給該方法
boolean onUnbind(Intent intent)

如果有新的客戶端連接至該服務(wù),只有當(dāng)舊的調(diào)用onUnbind()后拥诡,新的才會調(diào)用該方法
void onRebind(Intent intent)

補充:onCreate(Bundle savedInstanceState)與onSaveInstanceState(Bundle savedInstanceState)配合使用触趴,見如下代碼氮发,達(dá)到顯示activity被系統(tǒng)殺死前的狀態(tài)

 @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (null != savedInstanceState) { String _userid = savedInstanceState.getString("StrUserId"); String _uid = savedInstanceState.getString("StrUid"); String _serverid = savedInstanceState.getString("StrServerId"); String _servername = savedInstanceState.getString("StrServerName"); int _rate = savedInstanceState.getInt("StrRate"); //updateUserId(_userid); //updateUId(_uid); //updateServerId(_serverid); //updateUserServer(_servername); //updateRate(_rate); } } @Override protected void onSaveInstanceState(Bundle savedInstanceState) { super.onSaveInstanceState(savedInstanceState); savedInstanceState.putString("StrUserId", getUserId()); savedInstanceState.putString("StrUid", getUId()); savedInstanceState.putString("StrServerId", getServerId()); savedInstanceState.putString("StrServerName", getServerName()); savedInstanceState.putInt("StrRate", getRate()); }

引發(fā)activity摧毀和重建的其他情形
除了系統(tǒng)處于內(nèi)存不足的原因會摧毀activity之外, 某些系統(tǒng)設(shè)置的改變也會導(dǎo)致activity的摧毀和重建. 例如改變屏幕方向(見上例), 改變設(shè)備語言設(shè)定, 鍵盤彈出等.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市冗懦,隨后出現(xiàn)的幾起案子爽冕,更是在濱河造成了極大的恐慌,老刑警劉巖披蕉,帶你破解...
    沈念sama閱讀 219,490評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件颈畸,死亡現(xiàn)場離奇詭異,居然都是意外死亡没讲,警方通過查閱死者的電腦和手機(jī)眯娱,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來爬凑,“玉大人徙缴,你說我怎么就攤上這事∴倚牛” “怎么了于样?”我有些...
    開封第一講書人閱讀 165,830評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長吱抚。 經(jīng)常有香客問我百宇,道長,這世上最難降的妖魔是什么秘豹? 我笑而不...
    開封第一講書人閱讀 58,957評論 1 295
  • 正文 為了忘掉前任携御,我火速辦了婚禮,結(jié)果婚禮上既绕,老公的妹妹穿的比我還像新娘啄刹。我一直安慰自己,他們只是感情好凄贩,可當(dāng)我...
    茶點故事閱讀 67,974評論 6 393
  • 文/花漫 我一把揭開白布誓军。 她就那樣靜靜地躺著,像睡著了一般疲扎。 火紅的嫁衣襯著肌膚如雪昵时。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,754評論 1 307
  • 那天椒丧,我揣著相機(jī)與錄音壹甥,去河邊找鬼。 笑死壶熏,一個胖子當(dāng)著我的面吹牛句柠,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 40,464評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼溯职,長吁一口氣:“原來是場噩夢啊……” “哼精盅!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起谜酒,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤叹俏,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后甚带,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體她肯,經(jīng)...
    沈念sama閱讀 45,847評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,995評論 3 338
  • 正文 我和宋清朗相戀三年鹰贵,在試婚紗的時候發(fā)現(xiàn)自己被綠了晴氨。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,137評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡碉输,死狀恐怖籽前,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情敷钾,我是刑警寧澤枝哄,帶...
    沈念sama閱讀 35,819評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站阻荒,受9級特大地震影響挠锥,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜侨赡,卻給世界環(huán)境...
    茶點故事閱讀 41,482評論 3 331
  • 文/蒙蒙 一蓖租、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧羊壹,春花似錦蓖宦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至情妖,卻和暖如春睬关,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背毡证。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評論 1 272
  • 我被黑心中介騙來泰國打工电爹, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人情竹。 一個月前我還...
    沈念sama閱讀 48,409評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親秦效。 傳聞我的和親對象是個殘疾皇子雏蛮,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,086評論 2 355

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