1,Activity 生命周期
onCreate()? 創(chuàng)建?
onRestart() 重新啟動(dòng)?
onStart()啟動(dòng)? ?
onResume()可見?
onPause()正在停止,不能交互?
onStop()不可見?
onDestroy() 即將銷毀。
第一次啟動(dòng): onCreate() > onStart> onResume();
A activity 到B activity? ? ? ? A_onPause()>B_onCreate()>B_onStart()>B_onResume()>A_onStop()
B activity 返回A activity? ? B_onPause >A_onRestart()> A_onStart()> A_onResume()>B_onStop()>B_onDestroy()
顯示和隱藏標(biāo)準(zhǔn)的 AlertDialog 不會(huì)對(duì) MainActivity 的生命周期有任何的影響。
顯示和隱藏全屏的 AlertDialog 不會(huì)對(duì) MainActivity 的生命周期有任何的影響。
主題為 Dialog 的 Activity 會(huì)對(duì) MainActivity 的生命周期有影響,并且跳轉(zhuǎn)主題為 Dialog 的 Activity 與跳轉(zhuǎn)普通的 Activity 的生命周期變化相同。
橫豎屏切換時(shí)的生命周期調(diào)用為:onPause() -> onStop() -> onDestory() -> onCreate() -> onStart() -> onResume() 。就是一個(gè)銷毀再重建的過程。
將 MainActivity 的 android:configChanges 設(shè)置為 orientation【o:rui:ten:tion】?,之后切換橫豎屏并不會(huì)有任何的生命周期方法的調(diào)用
內(nèi)存不足時(shí),殺死應(yīng)用,前臺(tái)的 Activity 生命周期為 onPause() -> onStop()?并沒有調(diào)用 onDestory() 方法,所以主進(jìn)程現(xiàn)在屬于后臺(tái)進(jìn)程。
fragment被創(chuàng)建的時(shí)候,經(jīng)歷包含onAttach、onCreate、onCreateView、onActivityCreated方法;fragment對(duì)用戶可見的時(shí)候,經(jīng)歷包含onStart、onResume方法;fragment進(jìn)入“后臺(tái)模式”的時(shí)候,經(jīng)歷onPause、onStop方法;fragment被銷毀了(或者持有它的activity被銷毀了),經(jīng)歷包含onPause、onStop、onDestroyView、onDestroy、onDetach方法;并且可用onCreate、onCreateView、onActivityCreated方法Bundle對(duì)象保存一個(gè)fragment的對(duì)象。
onAttach:當(dāng)Fragment與Activity發(fā)生關(guān)聯(lián)時(shí)調(diào)用
onCreate:創(chuàng)建Fragment時(shí)被回調(diào),經(jīng)歷暫?;蛲V?fàn)顟B(tài)繼而恢復(fù)后,想保留Fragment的基本組件,則在此進(jìn)行初始化。
onCreateView:首次繪制頁面時(shí)候調(diào)用,在此可以創(chuàng)建View,也可以返回null,這樣不建議耗時(shí)操作。
onActivityCreated:Fragment綁定Activity,在onCreate方法已經(jīng)執(zhí)行完成并返回,在該方法內(nèi)可以進(jìn)行與Activity交互的UI操作,不能在此之前跟Activity進(jìn)行交互。
onStart:啟動(dòng) Fragment 時(shí)被回調(diào),此時(shí)Fragment可見,只是還沒有在前臺(tái)顯示,因此無法與用戶進(jìn)行交互
onResume:Fragment在前臺(tái)可見,處于活動(dòng)狀態(tài),用戶可與之交互
onPause:Fragment處于暫停狀態(tài),但依然可見,用戶不能與之交互
onStop:停止Fragment回調(diào),F(xiàn)ragment完全不可見
onDestoryView:銷毀與Fragment有關(guān)的視圖,但未與Activity解除綁定
onDestory:銷毀 Fragment 時(shí)被回調(diào),通常按Back鍵退出或者Fragment被回收時(shí)調(diào)用此方法,此后接onDetach
onDetach:與onAttach相對(duì)應(yīng),當(dāng)Fragment與Activity關(guān)聯(lián)被取消時(shí)調(diào)用
setUserVisibleHint:調(diào)用次方法可以設(shè)置Fragment可見或者不可見??梢哉{(diào)用getUserVisibleHint()獲得Fragment的可見或不可見狀態(tài),如果可見則進(jìn)行懶加載操作
在異常情況下,系統(tǒng)默認(rèn)恢復(fù) TextView 的文本信息
在切換橫豎屏?xí)r,onPause() 方法中打印了 TextView 的文本內(nèi)容,切換重建后,在 onResume() 中獲取到 TextView 的內(nèi)容與之前的內(nèi)容相同,并且要注意,重建后 onCreate() 與 onStart() 方法中獲取 TextView 的文本內(nèi)容是布局文件中的默認(rèn)內(nèi)容。
2, Activity 啟動(dòng)模式
standard 標(biāo)準(zhǔn)模式 每啟動(dòng)一個(gè)都會(huì)創(chuàng)建一個(gè)實(shí)例
singleTop 棧頂復(fù)用 如果在棧頂就調(diào)用onNewintent ,從onResume()開始
singleTask 棧內(nèi)復(fù)用 棧內(nèi)有,就復(fù)用,并將其上的Activity 移出
singleInstance 單例模式 系統(tǒng)會(huì)給該Activity 創(chuàng)建一個(gè)棧
3 .Service
onCreat()創(chuàng)建服務(wù)
onStartCommand()開始服務(wù)
onDestroy()銷毀服務(wù)
onBind()綁定服務(wù)
onUnbind()解綁服務(wù)
1)啟動(dòng)Service服務(wù)
單次:startService() —> onCreate() —> onStartCommand()
多次:startService() —> onCreate() —> onStartCommand() —> onStartCommand()
2)停止Service服務(wù)
stopService() —> onDestroy()
3)綁定Service服務(wù)
bindService() —> onCreate() —> onBind()
4)解綁Service服務(wù)
unbindService() —> onUnbind() —> onDestroy()
5)啟動(dòng)綁定Service服務(wù)
startService() —> onCreate() —> onStartCommand() —> bindService() —> onBind()
6)解綁停止Service服務(wù)
unbindService() —> onUnbind() —> stopService() —> onDestroy()
7)解綁綁定Service服務(wù)
unbindService() —> onUnbind(ture) —> bindService() —> onRebind()
8 ,stopSelf()也可以停止服務(wù)
。如果是多個(gè)組件綁定到一個(gè)服務(wù)上,當(dāng)綁定到該服務(wù)的所有組件都被銷毀時(shí),服務(wù)才會(huì)停止。
4,什么時(shí)候用Service
service是一個(gè)應(yīng)用組件,長時(shí)間運(yùn)行在后臺(tái),不需要直接跟用戶交互。
Service不是運(yùn)行在獨(dú)立的線程,所以不建議在Service中編寫耗時(shí)的邏輯和操作,否則會(huì)引起ANR。
1) 默認(rèn)情況下,Service其實(shí)是運(yùn)行在主線程中的,如果需要執(zhí)行復(fù)雜耗時(shí)的操作,必須在Service中再創(chuàng)建一個(gè)Thread來執(zhí)行任務(wù)。
(2) Service的優(yōu)先級(jí)高于后臺(tái)掛起的Activity,當(dāng)然,也高于Activity所創(chuàng)建的Thread,因此,系統(tǒng)可能在內(nèi)存不足的時(shí)候優(yōu)先殺死后臺(tái)的Activity或者Thread,而不會(huì)輕易殺死Service組件,即使被迫殺死Service,也會(huì)在資源可用時(shí)重啟被殺死的Service
在Service中創(chuàng)建的Thread,適合長期執(zhí)行一些獨(dú)立于APP的后臺(tái)任務(wù),比較常見的就是:在Service中保持與服務(wù)器端的長連接
5,intentService
Service不是運(yùn)行在獨(dú)立的線程,所以不建議在Service中編寫耗時(shí)的邏輯和操作,否則會(huì)引起ANR。
1,可用于執(zhí)行后臺(tái)耗時(shí)的任務(wù),任務(wù)執(zhí)行后會(huì)自動(dòng)停止。
2,具有高優(yōu)先級(jí),適合高優(yōu)先級(jí)的后臺(tái)任務(wù),且不容易被系統(tǒng)殺死。
3,可以多次啟動(dòng),每個(gè)耗時(shí)操作都會(huì)以工作隊(duì)列的方式在IntentService的onHandleIntent回調(diào)方法中執(zhí)行
內(nèi)部其實(shí)就是 HandlerThread + Handler ,? Handler發(fā)消息調(diào)用onHandleIntent()
執(zhí)行完任務(wù)會(huì) 執(zhí)行 stopSelf(), 自己會(huì)自殺,
優(yōu)先級(jí)高, 設(shè)為0 ,為高優(yōu)先級(jí)
6,Android 里的多線程
多線程的應(yīng)用在Android開發(fā)中是非常常見的,常用方法主要有:
繼承Thread類
實(shí)現(xiàn)Runnable接口
Handler
AsyncTask
HandlerThread
HandlerThread的本質(zhì):繼承Thread類 & 封裝Handler類
// 步驟1:創(chuàng)建HandlerThread實(shí)例對(duì)象
// 傳入?yún)?shù) = 線程名字,作用 = 標(biāo)記該線程
? HandlerThread mHandlerThread = new HandlerThread("handlerThread");
/ 步驟2:啟動(dòng)線程
? mHandlerThread.start();
// 步驟3:創(chuàng)建工作線程Handler & 復(fù)寫handleMessage()
// 作用:關(guān)聯(lián)HandlerThread的Looper對(duì)象、實(shí)現(xiàn)消息處理操作 & 與其他線程進(jìn)行通信
// 注:消息處理操作(HandlerMessage())的執(zhí)行線程 = mHandlerThread所創(chuàng)建的工作線程中執(zhí)行
? Handler workHandler = new Handler( handlerThread.getLooper() ) {
? ? ? ? ? ? @Override
? ? ? ? ? ? public boolean handleMessage(Message msg) {
? ? ? ? ? ? ? ? ...//消息處理
? ? ? ? ? ? ? ? return true;
? ? ? ? ? ? }
? ? ? ? });
// 步驟4:使用工作線程Handler向工作線程的消息隊(duì)列發(fā)送消息
// 在工作線程中,當(dāng)消息循環(huán)時(shí)取出對(duì)應(yīng)消息 & 在工作線程執(zhí)行相關(guān)操作
? // a. 定義要發(fā)送的消息
? Message msg = Message.obtain();
? msg.what = 2; //消息的標(biāo)識(shí)
? msg.obj = "B"; // 消息的存放
? // b. 通過Handler發(fā)送消息到其綁定的消息隊(duì)列
? workHandler.sendMessage(msg);
// 步驟5:結(jié)束線程,即停止線程的消息循環(huán)
? mHandlerThread.quit();
由run方法可知HandlerThrea線程運(yùn)行創(chuàng)建了Looper實(shí)例,并開啟了Looper循環(huán),循環(huán)從消息隊(duì)列中獲取消息并給Handler進(jìn)行處理。
注:子線程 用Handler 用法
7,Looper
1,主線程(UI線程)
UI線程中Looper已經(jīng)都創(chuàng)建好了,不用我們?nèi)?chuàng)建和循環(huán)。
2,普通線程
普通線程中使用Looper需要我們自己去prepare()、loop()。
看一下普通線程中創(chuàng)建使用Looper的方式,代碼如下:
class LooperThread extends Thread {
? ? public Handler mHandler;
? ? public void run() {
? ? ? ? Looper.prepare();
? ? ? ? mHandler = new Handler() {
? ? ? ? ? ? public void handleMessage(Message msg) {
? ? ? ? ? ? ? ? // process incoming messages here
? ? ? ? ? ? }
? ? ? ? };
? ? ? ? Looper.loop();
? }
}
印象中在UI線程沒有出現(xiàn)過Looper相關(guān)的東東,這是因?yàn)閁I線程中會(huì)自動(dòng)創(chuàng)建Looper對(duì)象并進(jìn)行消息循環(huán),我們不再需要調(diào)用Looper.prepare()和Looper.loop(),但是在子線程中如果想要?jiǎng)?chuàng)建使用Handelr則需要向如上所示。
我們通過源碼看一下Looper實(shí)例創(chuàng)建的方法:
public static void prepare() {
? ? prepare(true);
}
private static void prepare(boolean quitAllowed) {
? ? if (sThreadLocal.get() != null) {
? ? ? ? throw new RuntimeException("Only one Looper may be created per thread");
? ? }
? ? sThreadLocal.set(new Looper(quitAllowed));
}
sThreadLocal為ThreadLocal類型變量,用來存儲(chǔ)線程中的Looper對(duì)象。prepare方法中首先判斷sThreadLocal是否存儲(chǔ)對(duì)象,如果存儲(chǔ)了則拋出異常,這是因?yàn)樵谕粋€(gè)線程中Loop.prepare()方法不能調(diào)用兩次,也就是同一個(gè)線程中最多有一個(gè)Looper實(shí)例
接著看Looper的構(gòu)造器:
private Looper(boolean quitAllowed) {
? mQueue = new MessageQueue(quitAllowed);
? ? mRun = true;
? mThread = Thread.currentThread();
}
在構(gòu)造器中,創(chuàng)建了一個(gè)MessageQueue消息隊(duì)列;然后獲取當(dāng)前的線程,使Looper實(shí)例與線程綁定。由prepare方法可知一個(gè)線程只會(huì)有一個(gè)Looper實(shí)例,所以一個(gè)Looper實(shí)例也只有一個(gè)MessageQueue實(shí)例。但這并不代表一個(gè)線程只能有一個(gè)MessageQueue實(shí)例,這是為什么呢?很簡單,我們可以自己new 一個(gè)MessageQueue實(shí)例就可以了,但這個(gè)MessageQueue并不是該線程中Handelr對(duì)應(yīng)的消息隊(duì)列。
總結(jié):
UI線程會(huì)自動(dòng)創(chuàng)建Looper實(shí)例、并且調(diào)用loop()方法,不需要我們?cè)僬{(diào)用prepare()和loop().
Looper與創(chuàng)建它的線程綁定,確保一個(gè)線程最多有一個(gè)Looper實(shí)例,同時(shí)一個(gè)Looper實(shí)例只有一個(gè)MessageQueue實(shí)例。
loop()函數(shù)循環(huán)從MessageQueue中獲取消息,并將消息交給消息的target的dispatchMessage去處理。如果MessageQueue中沒有消息則獲取消息可能會(huì)阻塞。
通過調(diào)用Looper的quit或quitsafely終止消息循環(huán)。
相同點(diǎn):
將不在接受新的事件加入消息隊(duì)列。
不同點(diǎn)
當(dāng)我們調(diào)用Looper的quit方法時(shí),實(shí)際上執(zhí)行了MessageQueue中的removeAllMessagesLocked方法,該方法的作用是把MessageQueue消息池中所有的消息全部清空,無論是延遲消息(延遲消息是指通過sendMessageDelayed或通過postDelayed等方法發(fā)送的需要延遲執(zhí)行的消息)還是非延遲消息。
當(dāng)我們調(diào)用Looper的quitSafely方法時(shí),實(shí)際上執(zhí)行了MessageQueue中的removeAllFutureMessagesLocked方法,通過名字就可以看出,該方法只會(huì)清空MessageQueue消息池中所有的延遲消息,并將消息池中所有的非延遲消息派發(fā)出去讓Handler去處理,quitSafely相比于quit方法安全之處在于清空消息之前會(huì)派發(fā)所有的非延遲消息。
6, Parcelable 與 Serializable 區(qū)別
兩者最大的區(qū)別在于存儲(chǔ)媒介的不同,Serializable使用IO讀寫存儲(chǔ)在硬盤上,而Parcelable是直接在內(nèi)存中讀寫,很明顯內(nèi)存的讀寫速度通常大于IO讀寫,
android上應(yīng)該盡量采用Parcelable,效率至上
編碼上:
Serializable代碼量少,寫起來方便
Parcelable代碼多一些
效率上:
Parcelable的速度比高十倍以上
serializable的迷人之處在于你只需要對(duì)某個(gè)類以及它的屬性實(shí)現(xiàn)Serializable 接口即可。Serializable 接口是一種標(biāo)識(shí)接口(marker interface),這意味著無需實(shí)現(xiàn)方法,Java便會(huì)對(duì)這個(gè)對(duì)象進(jìn)行高效的序列化操作。
這種方法的缺點(diǎn)是使用了反射,序列化的過程較慢。這種機(jī)制會(huì)在序列化的時(shí)候創(chuàng)建許多的臨時(shí)對(duì)象,容易觸發(fā)垃圾回收。
Parcelable方式的實(shí)現(xiàn)原理是將一個(gè)完整的對(duì)象進(jìn)行分解,而分解后的每一部分都是Intent所支持的數(shù)據(jù)類型,這樣也就實(shí)現(xiàn)傳遞對(duì)象的功能了
7內(nèi)存抖動(dòng);
避免在ondraw()創(chuàng)建對(duì)象,因?yàn)槟銜?huì)頻繁創(chuàng)建只使用一次的對(duì)象,就會(huì)導(dǎo)致內(nèi)存的迅速攀升,就很可能觸犯GC的回收,
這種在短時(shí)間內(nèi)反復(fù)發(fā)生內(nèi)存增長和回收的循環(huán)。有界面卡頓的風(fēng)險(xiǎn)。Android 官方叫Memory churn
在onDraw()里創(chuàng)建對(duì)象往往跟繪制相關(guān),這些對(duì)象又經(jīng)常包含通往系統(tǒng)下層Native的對(duì)象引用,這就導(dǎo)致回收耗時(shí)會(huì)更高。
8 MVC、MVP 和 MVVM 區(qū)別
1.1 MVC
1.1.1 MVC三個(gè)字母的含義
View :對(duì)應(yīng)的XML文件
Model:實(shí)體類javabean
Controllor: 對(duì)應(yīng)Activity或者Fragment
? 1.1.3 優(yōu)缺點(diǎn)(以android的角度講)
優(yōu)點(diǎn)
Xml就是View層,與java邏輯代碼解耦,具有一定的解耦
缺點(diǎn)
沒有固定的model層,Activity中代表Controllor,網(wǎng)絡(luò)接口的model也在Activity中,一個(gè)邏輯稍微復(fù)雜的頁面代碼行數(shù)都上千行,影響閱讀,Activity既然控制著View,又含有Model。相當(dāng)耦合
2.2 MVP
2.2.1 MVP三個(gè)字母的含義
View 對(duì)應(yīng)于Activity和Xml,負(fù)責(zé)頁面的展示
Model 實(shí)體類javabean
Presenter 控制器 負(fù)責(zé)完成View于Model間的交互與邏輯處理(網(wǎng)絡(luò)和邏輯)
2.2.3 優(yōu)缺點(diǎn)
優(yōu)點(diǎn):
Model和View之間解耦,兩者交互由Presenter完成,把部分的邏輯的代碼從Fragment和Activity業(yè)務(wù)的邏輯移出來
Activity或者Fragment只是用來展示控件,或者控制控件的顯示和隱藏,以及View的變化
在MVP中View和presenter要相互持有,方便調(diào)用對(duì)方
缺點(diǎn):
隨著業(yè)務(wù)的增加,IView的接口和IPresenter的接口會(huì)越來越多
更換Xml里面的控件會(huì)引起IView接口和IPressenter接口的改動(dòng)
2.3 MVVM(只從android考慮)
2.3.1 MVVM三個(gè)字母的含義
View 還是Activity或者fragment,也就是Xml,負(fù)責(zé)頁面的展示,或者控制控件的顯示和隱藏,以及View的變化,不參與任何邏輯和數(shù)據(jù)的處理
Viewmodel 主要負(fù)責(zé)業(yè)務(wù)邏輯和數(shù)據(jù)處理,本身不持有 View 層引用,通過LiveData(如果項(xiàng)目中有Rxjava可以不引用LiveData) 向 View 層發(fā)送數(shù)據(jù),通過DataBinding更改View中的UI層
Model:實(shí)體類javabean,便是指這里的Repository ,主要負(fù)責(zé)從本地?cái)?shù)據(jù)庫或者遠(yuǎn)程服務(wù)器來獲取數(shù)據(jù),Repository統(tǒng)一了數(shù)據(jù)的入口,獲取到數(shù)據(jù),將數(shù)據(jù)發(fā)送?
2.3.3 優(yōu)缺點(diǎn)
優(yōu)點(diǎn) :
View和數(shù)據(jù)雙向綁定,當(dāng)model變化時(shí)會(huì)自動(dòng)同步給View
crash會(huì)降低,xml里面自己會(huì)有判斷
View(Activity或者Fragment)層就是View層,不處理任何關(guān)于數(shù)據(jù)的邏輯
缺點(diǎn) :
Xml里面寫代碼,對(duì)于android有點(diǎn)不習(xí)慣,并且會(huì)使xml臃腫
無法快速定位crash位置,Debug比較困難
雙向綁定不利于View的復(fù)用,因?yàn)槊總€(gè)xml里面都有一個(gè)model,但是每個(gè)頁面的mode有可能不一樣
xml里面寫java代碼,不能用kotlin的簡單語言
UI線程是不安全
悲觀鎖:
Binder 是基于文件的通信方式
RxJava
dispatch Touch Event? 事件分發(fā)
On Intercept? touch Event 是否攔截
On Touch Event? 消耗
ViewGroup和View 的dispatchTouchEvent 是做事件分發(fā),那么這個(gè)事件可能分發(fā)出去的四個(gè)目標(biāo)
注:------> 后面代表事件目標(biāo)需要怎么做。
1、 自己消費(fèi),終結(jié)傳遞。------->return true ;
2、 給自己的onTouchEvent處理-------> 調(diào)用super.dispatchTouchEvent()系統(tǒng)默認(rèn)會(huì)去調(diào)用 onInterceptTouchEvent,在onInterceptTouchEvent return true就會(huì)去把事件分給自己的onTouchEvent處理。
3、 傳給子View------>調(diào)用super.dispatchTouchEvent()默認(rèn)實(shí)現(xiàn)會(huì)去調(diào)用 onInterceptTouchEvent 在onInterceptTouchEvent return false,就會(huì)把事件傳給子類。
4、 不傳給子View,事件終止往下傳遞,事件開始回溯,從父View的onTouchEvent開始事件從下到上回歸執(zhí)行每個(gè)控件的onTouchEvent------->return false;
注:?由于View沒有子View所以不需要onInterceptTouchEvent 來控件是否把事件傳遞給子View還是攔截,所以View的事件分發(fā)調(diào)用super.dispatchTouchEvent()的時(shí)候默認(rèn)把事件傳給自己的onTouchEvent處理(相當(dāng)于攔截),對(duì)比ViewGroup的dispatchTouchEvent 事件分發(fā),View的事件分發(fā)沒有上面提到的4個(gè)目標(biāo)的第3點(diǎn)。
ViewGroup和View的onTouchEvent方法是做事件處理的,那么這個(gè)事件只能有兩個(gè)處理方式:
1、自己消費(fèi)掉,事件終結(jié),不再傳給誰----->return true;
2、繼續(xù)從下往上傳,不消費(fèi)事件,讓父View也能收到到這個(gè)事件----->return false;View的默認(rèn)實(shí)現(xiàn)是不消費(fèi)的。所以super==false。
ViewGroup的onInterceptTouchEvent方法對(duì)于事件有兩種情況:
1、攔截下來,給自己的onTouchEvent處理--->return true;
2、不攔截,把事件往下傳給子View---->return false,ViewGroup默認(rèn)是不攔截的,所以super==false;