Activity
Activity 頁面單元 負責頁面的顯示與交互
生命周期1

1.生命周期
onCreate()
Activity初始化操作:設(shè)置布局,初始化視圖,綁定事件等。方法中有一個bundle參數(shù)用于恢復activity意外銷毀時保存的數(shù)據(jù),bundle不為空,取數(shù)據(jù)。
onStart()
這個方法在活動由不可見變?yōu)榭梢姷臅r候調(diào)用。
onResume()
Activity變?yōu)榭梢?執(zhí)行完onResume()之后, Activity就會請求AMS渲染它所管理的視圖。此時的Activity位于返回棧的棧頂,并且處于運行狀態(tài)。這個方法在活動獲得焦點,準備好和用戶進行交互的時候調(diào)用。
onPause()
在另一個活動來到前臺時調(diào)用,部分可見。在這個函數(shù)中將一些消耗cpu的資源釋放掉,保存一些關(guān)鍵數(shù)據(jù)。
返回上一個活動經(jīng)歷:onPause()-->onResume()
onStop()
Activity完全不可見時調(diào)用。
返回上一個活動經(jīng)歷:onStop()-->onRestart()-->onStart()
onDestory()
銷毀時得到調(diào)用,釋放內(nèi)存。
onRestart()
在停止狀態(tài)(onstop)返回上一個活動,變成運行狀態(tài)(onstart)之前調(diào)用。
在 onCreate()方法和 onDestroy() 方法之間所經(jīng)歷的,就是完整生存期。
活動在 onStart() 方法和 onStop() 方法之間所經(jīng)歷的,就是可見生存期。在可見生存期內(nèi), 活動對于用戶總是可見的, 即便有可能無法和用戶進行交互。 我們可以通過這兩個方法,合理地管理那些對用戶可見的資源。比如在 onStart() 方法中對資源進行加載,而在 onStop() 方法中對資源進行釋放, 從而保證處于停止狀態(tài)的活動不會占用過多內(nèi)存。
在 onResume() 方法和 onPause() 方法之間所經(jīng)歷的,就是前臺生存期。在前臺生存期內(nèi), 活動總是處于運行狀態(tài)的, 此時的活動是可以和用戶進行相互的, 我們平時看到和接觸最多的也這個狀態(tài)下的活動。
典型生命周期總結(jié)
當經(jīng)歷onPause和onStop時,如果遇到更高優(yōu)先級的程序需要內(nèi)存,將需要殺掉進程,重新返回到onCreate()。
點擊back鍵經(jīng)歷的生命周期:onPause()-->onStop()-->onDestory ()
點擊back鍵再返回應用經(jīng)歷的生命周期:(因為活動已經(jīng)銷毀,需要重新創(chuàng)建)onCreate -->onStart-->....
點擊home鍵經(jīng)歷的生命周期:onPause()-->onStop()
點擊home鍵后再返回應用的生命周期:onRestart()-->onStart()....
關(guān)于使用dialog的生命周期
把Activity的Theme設(shè)置成Dialog【android:theme="@android:style/Theme.Dialog"】,這樣Activity顯示成Dialog,本質(zhì)還是Activity。擁有Activity的生命周期函數(shù)和特性 。但調(diào)轉(zhuǎn)詞activity的效果是和dialog一樣的,此時在Activity A中啟動這樣的Dialog B,這時Activity A會運行onPause,退出Dialog B時,Activity A會運行onResume。
一個對話框來到前臺:onPause()
但是還有一種,是使用Dialog,而不是具有Dialog屬性的Activity,這時,在Activity A中啟動Dialog B,如在onCreate中啟動,肯定是會接著運行onStart,onResume等的,但是是不會運行onPause的。退出Dialog B,Activity A不會運行周期函數(shù),也就是不會走onResume()。
A頁面-B頁面跳轉(zhuǎn) 若B覆蓋A: onPause(A)-onCreate(B)-onStart(B)-onResume(B)-onStop(A)
此時B頁面按back鍵返回 :onPause(B)-onRestart(A)-onStart(A)-onResume(A)-onStop(B)-onDestory(B)
A頁面-B頁面跳轉(zhuǎn) 若B透明,沒有覆蓋A:onPause(A)-onCreate(B)-onStart(B)-onResume(B)
橫豎屏切換:不設(shè)置Activity的android:configChanges時,切屏會重新調(diào)用各個生命周期,切橫屏時會執(zhí)行一次,切豎屏時會執(zhí)行兩次。
Activity退出生命周期:
結(jié)束一個活動:Activity---finish –>onpause onstop ondestory
結(jié)束進程:android.os.Process.killProcess(android.os.Process.myPid());System.exit(int code) 這兩個方法,會使activity非正常退出,不會去執(zhí)行onpause onstop ondestory
2.InstanceState
InstanceState用來保存和恢復數(shù)據(jù)功能,主要時onSaveInstanceState() 和 onRestoreInstanceState() 。關(guān)于這兩個方法,在應用程序在不知道的情況下退出后,可以實現(xiàn)其數(shù)據(jù)保存的功能。Activity的 onSaveInstanceState() 和 onRestoreInstanceState()并不是生命周期方法,它們不同于 onCreate()、onPause()等生命周期方法,它們并不一定會被觸發(fā)。
當應用遇到意外情況(如:內(nèi)存不足、用戶直接按Home鍵、橫豎屏切換 即當某個activity變得"容易"被系統(tǒng)銷毀時)由系統(tǒng)銷毀一個Activity時,onSaveInstanceState() 會被調(diào)用。但是當用戶主動去銷毀一個Activity時,例如在應用中按返回鍵,手動調(diào)用finish() 等,onSaveInstanceState()就不會被調(diào)用。因為在這種情況下,用戶的行為決定了不需要保存Activity的狀態(tài)。通常onSaveInstanceState()只適合用于保存一些臨時性的狀態(tài),而onPause()適合用于數(shù)據(jù)的持久化保存。
劃重點:onSavedInstanceState中保存的是瞬時數(shù)據(jù)。onpause中保存的時持久化數(shù)據(jù)。
onSaveInstanceState() 的調(diào)用更多時是在onPause()方法之前,有時也在onStop()方法之前。這個方法在一個activity被殺死前調(diào)用(onSaveInstanceState將需要保存的狀態(tài)封裝在Bundle中:調(diào)用View的onSaveInstanceState (),返回Parcelable對象,接著用Bundle的putParcelable方法保存在Bundle savedInstanceState中。)當該activity在將來某個時刻回來時可以在onCreate(Bundle)或者onRestoreInstanceState(Bundle)恢復其先前狀態(tài)。 (當系統(tǒng)調(diào)用Activity的的onRestoreInstanceState(Bundle savedInstanceState)時, 同過Bundle的getParcelable方法得到Parcelable對象,然后把該Parcelable對象傳給View的onRestoreInstanceState (Parcelable state)。在的View的onRestoreInstanceState中從Parcelable讀取保存的數(shù)據(jù)以便View使用。)
onRestoreInstanceState()在onStart() 和 onPostCreate(Bundle)之間調(diào)用。他和onSaveInstanceState()不一定是成對使用的,例如,當正在顯示activity A的時候,用戶按下HOME鍵回到主界面,然后用戶緊接著又返回到activity A,這種情況下activity A一般不會因為內(nèi)存的原因被系統(tǒng)銷毀,故activity A的onRestoreInstanceState方法不會被執(zhí)行 。
3.Activity的構(gòu)成
需要了解在Activity和xml之間隔著 Window和 DecorView ,一張圖示了解他們的層級關(guān)系。
層級關(guān)系
4.Activity的啟動模式
developer--model
在AndroidManifest.xml中在注冊activity時設(shè)置它的啟動模式 android:launchMode="standard"
android內(nèi)部使用通過回退棧來管理activity實例。棧是一種后進先出的集合。activity的四種啟動模式為:standard,singleTop,singleTask,singleInstance.
1.standard:標準啟動模式,是activity默認的啟動模式,這個模式下的activity可以被多次實例化。
2.singleTop:單一棧頂模式,如果以singleTop模式啟動的Activity 的實例已經(jīng)存在于任務(wù)棧的棧頂,那么再啟動這個Activity時,將使用棧頂實例,不會重新創(chuàng)建。但若在任務(wù)棧中,卻不在棧頂,那么還是會重新創(chuàng)建新的實例。

3.singleTask:單一任務(wù)棧模式,(即在一個任務(wù)棧中只能有一個該activity 的實例),沒有會重新創(chuàng)建,如果已經(jīng)存在activity,系統(tǒng)則會銷毀處在該activity上的所有activity,最終讓activity處于棧頂,同時回調(diào)該activity的onNewIntent()函數(shù)。
即在同一個進程中,若啟動一個singletask模式的activity,看當前進程的任務(wù)棧中是否存在該activity 如果不存在,創(chuàng)建activtiy 如果存在,將該activity上面的其他activtiy銷毀,并回調(diào)該activity的onnewintent。

4.singleInstance:單一實例模式,(即保證activity系統(tǒng)只有一個實例),設(shè)置該模式的實例,會在一個獨立的任務(wù)棧中開啟,并且這個新的任務(wù)棧中有且只有這一個實例,不會要其他的activtiy和它共存在同一個任務(wù)棧中,如果這個實例想再去啟動activityc,activityc就會到其他或創(chuàng)建新的任務(wù)棧中去。

singleTask和singleInstance:
相同點:
兩者相同的是,它們只能啟動任務(wù)。 它們始終位于 Activity 堆棧的根位置。一個任務(wù)棧中只能有一個該activity的實例。
不同點:
“singleTask”Activity 允許其他 Activity 成為其任務(wù)的組成部分。 它始終位于其任務(wù)的根位置,但其他 Activity(必然是“standard”和“singleTop”Activity)可以啟動到該任務(wù)中。 相反,“singleInstance”Activity 則不允許其他 Activity 成為其任務(wù)的組成部分。它是任務(wù)中唯一的 Activity。 如果它啟動另一個 Activity,系統(tǒng)會將該 Activity 分配給其他任務(wù) — 就好像 Intent 中包含 FLAG_ACTIVITY_NEW_TASK 一樣。
FLAG_ACTIVITY_NEW_TASK
當Intent對象包含這個標記時,系統(tǒng)會尋找或創(chuàng)建一個新的task來放置目標Activity,尋找時依據(jù)目標Activity的taskAffinity屬性進行匹配,如果找到一個task的taskAffinity與之相同,就將目標Activity壓入此task中,如果查找無果,則創(chuàng)建一個新的task,并將該task的taskAffinity設(shè)置為目標Activity的taskActivity,將目標Activity放置于此task。注意,如果同一個應用中Activity的taskAffinity都使用默認值或都設(shè)置相同值時,應用內(nèi)的Activity之間的跳轉(zhuǎn)使用這個標記是沒有意義的,因為當前應用task就是目標Activity最好的宿主。
啟動模式和生命周期
Service
Service 負責與UI無關(guān)的工作 【后臺】執(zhí)行的操作
Android的后臺就是指,它的運行是完全不依賴UI的。即使Activity被銷毀,或者程序被關(guān)閉,只要進程還在,Service就可以繼續(xù)運行。
1.開啟 Service
方式一:startService()
注意生命周期:當通過startService() 啟動一個Service的時候,會調(diào)用該Service中的onCreate()和onStartCommand()方法。當再次調(diào)用startService(),這次只有onStartCommand()方法執(zhí)行了,onCreate()方法并沒有執(zhí)行。因為onCreate()只會在創(chuàng)建時執(zhí)行一次。不管創(chuàng)建多少次,調(diào)用一次stopService()或stopSelf() 將會停止服務(wù)。
方式二:bindService()
bindService()相比startService()多了與Activity之間的關(guān)系,綁定了Activity。調(diào)用這個方法會使Service中的onCreate()方法得到執(zhí)行,但onStartCommand()方法不會執(zhí)行。此時如果想解除Activity和Service之間的關(guān)聯(lián),調(diào)用一下unbindService()方法就可以了。
如果我們既調(diào)用了startService()又調(diào)用了bindService(),此時單獨執(zhí)行stopService()或unbindService()都不能使服務(wù)停止,必要將兩個方法都執(zhí)行,Service才會被銷毀。也就是說,調(diào)用stopService()只會讓Service停止,調(diào)用unbindService()只會讓Service和Activity解除關(guān)聯(lián),【一個Service必須要在既沒有和任何Activity關(guān)聯(lián)又處理停止狀態(tài)的時候才會被銷毀?!?/p>
2.生命周期
對于startService() 方式啟動Service:創(chuàng)建服務(wù)onCreate() 開始服務(wù)onStartCommand() 銷毀服務(wù)onDestory() 【一個服務(wù)會被創(chuàng)建一次,銷毀一次,但是會開始多次。】
對于bindService()方式啟動Service:onCreate() onBind() onUnbind() onDestory()【采用bind方式 和activity綁定,一但銷毀activity,與之綁定的service也就相應結(jié)束。“不求同時生,必須同時死”】
只使用startService啟動服務(wù)的生命周期:

只使用BindService綁定服務(wù)的生命周期:

同時使用startService()啟動服務(wù)、BindService()綁定服務(wù)的生命周期:

3.切記混淆服務(wù)與線程,要注意的是服務(wù)執(zhí)行在UI 線程中,所以不要在Service中執(zhí)行【耗時操作】,除非在Service中創(chuàng)建了子線程來完成耗時操作。這些耗時邏輯,需要在service中創(chuàng)建子線程。既然在Service里也要創(chuàng)建一個子線程,那為什么不直接在Activity里創(chuàng)建呢?這是因為Activity很難對Thread進行控制,當Activity被銷毀之后,就沒有任何其它的辦法可以再重新獲取到之前創(chuàng)建的子線程的實例。而且在一個Activity中創(chuàng)建的子線程,另一個Activity無法對其進行操作。但是Service就不同了,所有的Activity都可以與Service進行關(guān)聯(lián),然后可以很方便地操作其中的方法,即使Activity被銷毀了,之后只要重新與Service建立關(guān)聯(lián),就又能夠獲取到原有的Service中Binder的實例。因此,使用Service來處理后臺任務(wù),Activity就可以放心地finish,完全不需要擔心無法對后臺任務(wù)進行控制的情況。
4.IntentService : 將用戶的請求執(zhí)行在一個子線程中,用戶只需要復寫onHandleIntent函數(shù),并且在函數(shù)中完成自己的耗時操作即可。需要注意的是,在任務(wù)執(zhí)行完畢之后IntentService會調(diào)用stopSelf自我銷毀。所以它適用于完成一些短期的耗時任務(wù)。
5.Service默認是運行在后臺,但在后臺優(yōu)先級比較低,當系統(tǒng)內(nèi)存不足時,很有可能被回收。如果希望Service可以一直保持運行狀態(tài),可以將 Service運行在前臺。前臺Service和普通Service最大的區(qū)別就在于,它會一直有一個正在運行的圖標在系統(tǒng)的狀態(tài)欄顯示,下拉狀態(tài)欄后可以看到更加詳細的信息,非常類似于通知的效果。
6.AIDL
如果當前Activity要與另一個進程的服務(wù)建立連接,這就要使用AIDL來進行跨進程通信(IPC)了。
AIDL接口描述語言,通常用于進程間通信。它可以用于讓某個Service與多個應用程序組件之間進行跨進程通信,從而可以實現(xiàn)多個應用程序共享同一個Service的功能。查閱資料了解AIDL的使用和原理。推薦文章1&&推薦文章2
Broadcast
Broadcast 組件間、應用間通信
android中的廣播就像我們平時說的電臺廣播,一個廣播可以有多個接受者,廣播機制是一個典型的發(fā)布-訂閱模式(觀察者模式)。廣播機制最大的特點就是發(fā)送方并不關(guān)心接受方是否接受或是如何處理數(shù)據(jù)的,這樣接收雙方完全解耦合。
廣播機制主要包含三個要素,發(fā)送廣播的BroadCast 、接收廣播的BroadCastReceiver、用于傳遞信息的Intent。
1.注冊方式:
靜態(tài)注冊 AndroidManifast.xml中,只要app在運行就一直能接收到廣播。
動態(tài)注冊 在activity或service中注冊,它們?nèi)舯讳N毀,廣播也就接受不到了。
2.生命周期:onReceive()
生命周期只有十秒左右,如果在 onReceive() 內(nèi)做超過十秒內(nèi)的事情,就會報ANR 程序無響應的錯誤信息。
如果需要完成一項比較耗時的工作 , 應該通過發(fā)送 Intent 給 Service, 由Service 來完成。
不要在廣播接受者中創(chuàng)建子線程,因為它的生命周期非常短,子線程可能還沒有結(jié)束BroadcastReceiver 就先結(jié)束了,子線程相應也就結(jié)束了。
3.類型:Android廣播主要分為普通廣播、有序廣播、本地廣播、 Sticky廣播。
普通廣播:
sendBroadcast(Intent intent)發(fā)送廣播
優(yōu)點:效率高
缺點:一個接受者不能將處理結(jié)果傳遞給下一個接受者,并且無法終止廣播的傳播。完全異步,接收器的執(zhí)行順序不確定。
有序廣播:
sendOrderedBroadcast(intent, receiverPermission)
缺點:效率低
優(yōu)點:按優(yōu)先級別由高到低依次傳播,高級別的或同級別先接收到廣播的可以通過abortBroadcast()方法截斷廣播使其他的接收者無法收到該廣播。也可以通過setResultExtras(bundle)方法將處理結(jié)果存入bundle中,下一個接受可以通過getResultExtra(true) 方法獲取上一個接受者傳來的bundle數(shù)據(jù)。
本地廣播:
LocalBroadcastManager 普通廣播和有序廣播都是全局廣播,所有應用程序都可以接收到,這樣就會帶來安全隱患。但是有的時候我們并不需要把自己的應用內(nèi)的信息廣播給所有應用,而只是在進程內(nèi)使用。所以使用本地廣播就能實現(xiàn)限于應用內(nèi)的廣播。本地廣播和普通廣播只是操作的類不一樣,其他接口都類似,只需把從前的registerReceiver()變成LocalBroadcastManager.getInstance(context).registerReceiver()。替換成本比較低,為了程序的安全性,建議在不需要其他進程接收廣播的情況下使用本地廣播。
Sticky廣播:
sendStickyBroadcast 用此函數(shù)發(fā)送的廣播會一直滯留,當有匹配此廣播的廣播接收器被注冊后,該廣播接收器就會收到此條廣播。(記得在AndroidManifest 里注冊BROADCAST_STICKY權(quán)限)。sendStickyBroadcast只保留最后一條廣播,并且一直保留下去,這樣即使已經(jīng)有廣播接收器處理了該廣播,當再有匹配的廣播接收器被注冊時,次廣播仍然會被接收。如果你只想處理一遍該廣播,可以通過removeStickyBroadcast()函數(shù)實現(xiàn)。
ContentProvider
ContentProvider 應用間數(shù)據(jù)共享 使用其對外共享數(shù)據(jù)的好處是統(tǒng)一了數(shù)據(jù)的訪問方式,實際上是對SQliteOpenHelper 的進一步封裝,通過Uri地址映射來判斷選擇需要操作數(shù)據(jù)庫中的哪個表,并且進行增刪改查處理。
Content Provider 內(nèi)容提供者,用于對外提供數(shù)據(jù)
Content Resolver 內(nèi)容解析者,用戶獲取提供者提供的數(shù)據(jù)(外部應用通過resolver來訪問provider)
Content Observer 內(nèi)容監(jiān)聽器,可以監(jiān)聽數(shù)據(jù)的改變狀態(tài)
使用Content Provider對外共享數(shù)據(jù)的步驟:
定義一個類繼承Content Provider,然后重寫query、insert、delete、update方法等
參考文章

