1,Activity 生命周期
onCreate()? 創(chuàng)建?
onRestart() 重新啟動?
onStart()啟動? ?
onResume()可見?
onPause()正在停止注暗,不能交互?
onStop()不可見?
onDestroy() 即將銷毀磷醋。
第一次啟動: 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)準的 AlertDialog 不會對 MainActivity 的生命周期有任何的影響猫牡。
顯示和隱藏全屏的 AlertDialog 不會對 MainActivity 的生命周期有任何的影響。
主題為 Dialog 的 Activity 會對 MainActivity 的生命周期有影響邓线,并且跳轉(zhuǎn)主題為 Dialog 的 Activity 與跳轉(zhuǎn)普通的 Activity 的生命周期變化相同淌友。
橫豎屏切換時的生命周期調(diào)用為:onPause() -> onStop() -> onDestory() -> onCreate() -> onStart() -> onResume() 。就是一個銷毀再重建的過程褂痰。
將 MainActivity 的 android:configChanges 設(shè)置為 orientation【o:rui:ten:tion】?,之后切換橫豎屏并不會有任何的生命周期方法的調(diào)用
內(nèi)存不足時症虑,殺死應(yīng)用缩歪,前臺的 Activity 生命周期為 onPause() -> onStop()?并沒有調(diào)用 onDestory() 方法,所以主進程現(xiàn)在屬于后臺進程谍憔。
fragment被創(chuàng)建的時候匪蝙,經(jīng)歷包含onAttach、onCreate习贫、onCreateView逛球、onActivityCreated方法;fragment對用戶可見的時候苫昌,經(jīng)歷包含onStart颤绕、onResume方法;fragment進入“后臺模式”的時候,經(jīng)歷onPause奥务、onStop方法物独;fragment被銷毀了(或者持有它的activity被銷毀了),經(jīng)歷包含onPause氯葬、onStop挡篓、onDestroyView、onDestroy帚称、onDetach方法官研;并且可用onCreate、onCreateView闯睹、onActivityCreated方法Bundle對象保存一個fragment的對象戏羽。
onAttach:當(dāng)Fragment與Activity發(fā)生關(guān)聯(lián)時調(diào)用
onCreate:創(chuàng)建Fragment時被回調(diào),經(jīng)歷暫驼鞍樱或停止?fàn)顟B(tài)繼而恢復(fù)后蛛壳,想保留Fragment的基本組件,則在此進行初始化所刀。
onCreateView:首次繪制頁面時候調(diào)用衙荐,在此可以創(chuàng)建View,也可以返回null浮创,這樣不建議耗時操作忧吟。
onActivityCreated:Fragment綁定Activity,在onCreate方法已經(jīng)執(zhí)行完成并返回斩披,在該方法內(nèi)可以進行與Activity交互的UI操作溜族,不能在此之前跟Activity進行交互。
onStart:啟動 Fragment 時被回調(diào)垦沉,此時Fragment可見煌抒,只是還沒有在前臺顯示,因此無法與用戶進行交互
onResume:Fragment在前臺可見厕倍,處于活動狀態(tài)寡壮,用戶可與之交互
onPause:Fragment處于暫停狀態(tài),但依然可見讹弯,用戶不能與之交互
onStop:停止Fragment回調(diào)况既,F(xiàn)ragment完全不可見
onDestoryView:銷毀與Fragment有關(guān)的視圖,但未與Activity解除綁定
onDestory:銷毀 Fragment 時被回調(diào)组民,通常按Back鍵退出或者Fragment被回收時調(diào)用此方法棒仍,此后接onDetach
onDetach:與onAttach相對應(yīng),當(dāng)Fragment與Activity關(guān)聯(lián)被取消時調(diào)用
setUserVisibleHint:調(diào)用次方法可以設(shè)置Fragment可見或者不可見臭胜∧洌可以調(diào)用getUserVisibleHint()獲得Fragment的可見或不可見狀態(tài)癞尚,如果可見則進行懶加載操作
在異常情況下,系統(tǒng)默認恢復(fù) TextView 的文本信息
在切換橫豎屏?xí)r榜配,onPause() 方法中打印了 TextView 的文本內(nèi)容否纬,切換重建后,在 onResume() 中獲取到 TextView 的內(nèi)容與之前的內(nèi)容相同蛋褥,并且要注意临燃,重建后 onCreate() 與 onStart() 方法中獲取 TextView 的文本內(nèi)容是布局文件中的默認內(nèi)容。
2烙心, Activity 啟動模式
standard 標(biāo)準模式 每啟動一個都會創(chuàng)建一個實例
singleTop 棧頂復(fù)用 如果在棧頂就調(diào)用onNewintent ,從onResume()開始
singleTask 棧內(nèi)復(fù)用 棧內(nèi)有膜廊,就復(fù)用,并將其上的Activity 移出
singleInstance 單例模式 系統(tǒng)會給該Activity 創(chuàng)建一個棧
3 .Service
onCreat()創(chuàng)建服務(wù)
onStartCommand()開始服務(wù)
onDestroy()銷毀服務(wù)
onBind()綁定服務(wù)
onUnbind()解綁服務(wù)
1)啟動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)啟動綁定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ù)
淫茵。如果是多個組件綁定到一個服務(wù)上爪瓜,當(dāng)綁定到該服務(wù)的所有組件都被銷毀時,服務(wù)才會停止匙瘪。
4,什么時候用Service
service是一個應(yīng)用組件铆铆,長時間運行在后臺,不需要直接跟用戶交互丹喻。
Service不是運行在獨立的線程薄货,所以不建議在Service中編寫耗時的邏輯和操作,否則會引起ANR碍论。
1) 默認情況下谅猾,Service其實是運行在主線程中的,如果需要執(zhí)行復(fù)雜耗時的操作鳍悠,必須在Service中再創(chuàng)建一個Thread來執(zhí)行任務(wù)税娜。
(2) Service的優(yōu)先級高于后臺掛起的Activity,當(dāng)然藏研,也高于Activity所創(chuàng)建的Thread敬矩,因此,系統(tǒng)可能在內(nèi)存不足的時候優(yōu)先殺死后臺的Activity或者Thread蠢挡,而不會輕易殺死Service組件弧岳,即使被迫殺死Service,也會在資源可用時重啟被殺死的Service
在Service中創(chuàng)建的Thread袒哥,適合長期執(zhí)行一些獨立于APP的后臺任務(wù)缩筛,比較常見的就是:在Service中保持與服務(wù)器端的長連接
5消略,intentService
Service不是運行在獨立的線程堡称,所以不建議在Service中編寫耗時的邏輯和操作,否則會引起ANR艺演。
1,可用于執(zhí)行后臺耗時的任務(wù)却紧,任務(wù)執(zhí)行后會自動停止桐臊。
2,具有高優(yōu)先級,適合高優(yōu)先級的后臺任務(wù)晓殊,且不容易被系統(tǒng)殺死断凶。
3,可以多次啟動,每個耗時操作都會以工作隊列的方式在IntentService的onHandleIntent回調(diào)方法中執(zhí)行
內(nèi)部其實就是 HandlerThread + Handler ,? Handler發(fā)消息調(diào)用onHandleIntent()
執(zhí)行完任務(wù)會 執(zhí)行 stopSelf(), 自己會自殺巫俺,
優(yōu)先級高认烁, 設(shè)為0 ,為高優(yōu)先級
6介汹,Android 里的多線程
多線程的應(yīng)用在Android開發(fā)中是非常常見的却嗡,常用方法主要有:
繼承Thread類
實現(xiàn)Runnable接口
Handler
AsyncTask
HandlerThread
HandlerThread的本質(zhì):繼承Thread類 & 封裝Handler類
// 步驟1:創(chuàng)建HandlerThread實例對象
// 傳入?yún)?shù) = 線程名字,作用 = 標(biāo)記該線程
? HandlerThread mHandlerThread = new HandlerThread("handlerThread");
/ 步驟2:啟動線程
? mHandlerThread.start();
// 步驟3:創(chuàng)建工作線程Handler & 復(fù)寫handleMessage()
// 作用:關(guān)聯(lián)HandlerThread的Looper對象嘹承、實現(xiàn)消息處理操作 & 與其他線程進行通信
// 注:消息處理操作(HandlerMessage())的執(zhí)行線程 = mHandlerThread所創(chuàng)建的工作線程中執(zhí)行
? Handler workHandler = new Handler( handlerThread.getLooper() ) {
? ? ? ? ? ? @Override
? ? ? ? ? ? public boolean handleMessage(Message msg) {
? ? ? ? ? ? ? ? ...//消息處理
? ? ? ? ? ? ? ? return true;
? ? ? ? ? ? }
? ? ? ? });
// 步驟4:使用工作線程Handler向工作線程的消息隊列發(fā)送消息
// 在工作線程中窗价,當(dāng)消息循環(huán)時取出對應(yīng)消息 & 在工作線程執(zhí)行相關(guān)操作
? // a. 定義要發(fā)送的消息
? Message msg = Message.obtain();
? msg.what = 2; //消息的標(biāo)識
? msg.obj = "B"; // 消息的存放
? // b. 通過Handler發(fā)送消息到其綁定的消息隊列
? workHandler.sendMessage(msg);
// 步驟5:結(jié)束線程,即停止線程的消息循環(huán)
? mHandlerThread.quit();
由run方法可知HandlerThrea線程運行創(chuàng)建了Looper實例叹卷,并開啟了Looper循環(huán)撼港,循環(huán)從消息隊列中獲取消息并給Handler進行處理。
注:子線程 用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)的東東否灾,這是因為UI線程中會自動創(chuàng)建Looper對象并進行消息循環(huán),我們不再需要調(diào)用Looper.prepare()和Looper.loop()鸣奔,但是在子線程中如果想要創(chuàng)建使用Handelr則需要向如上所示墨技。
我們通過源碼看一下Looper實例創(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類型變量,用來存儲線程中的Looper對象挎狸。prepare方法中首先判斷sThreadLocal是否存儲對象扣汪,如果存儲了則拋出異常,這是因為在同一個線程中Loop.prepare()方法不能調(diào)用兩次锨匆,也就是同一個線程中最多有一個Looper實例
接著看Looper的構(gòu)造器:
private Looper(boolean quitAllowed) {
? mQueue = new MessageQueue(quitAllowed);
? ? mRun = true;
? mThread = Thread.currentThread();
}
在構(gòu)造器中崭别,創(chuàng)建了一個MessageQueue消息隊列;然后獲取當(dāng)前的線程恐锣,使Looper實例與線程綁定茅主。由prepare方法可知一個線程只會有一個Looper實例,所以一個Looper實例也只有一個MessageQueue實例土榴。但這并不代表一個線程只能有一個MessageQueue實例诀姚,這是為什么呢?很簡單玷禽,我們可以自己new 一個MessageQueue實例就可以了赫段,但這個MessageQueue并不是該線程中Handelr對應(yīng)的消息隊列呀打。
總結(jié):
UI線程會自動創(chuàng)建Looper實例、并且調(diào)用loop()方法糯笙,不需要我們再調(diào)用prepare()和loop().
Looper與創(chuàng)建它的線程綁定贬丛,確保一個線程最多有一個Looper實例,同時一個Looper實例只有一個MessageQueue實例给涕。
loop()函數(shù)循環(huán)從MessageQueue中獲取消息豺憔,并將消息交給消息的target的dispatchMessage去處理。如果MessageQueue中沒有消息則獲取消息可能會阻塞够庙。
通過調(diào)用Looper的quit或quitsafely終止消息循環(huán)焕阿。
相同點:
將不在接受新的事件加入消息隊列。
不同點
當(dāng)我們調(diào)用Looper的quit方法時首启,實際上執(zhí)行了MessageQueue中的removeAllMessagesLocked方法暮屡,該方法的作用是把MessageQueue消息池中所有的消息全部清空,無論是延遲消息(延遲消息是指通過sendMessageDelayed或通過postDelayed等方法發(fā)送的需要延遲執(zhí)行的消息)還是非延遲消息毅桃。
當(dāng)我們調(diào)用Looper的quitSafely方法時褒纲,實際上執(zhí)行了MessageQueue中的removeAllFutureMessagesLocked方法,通過名字就可以看出钥飞,該方法只會清空MessageQueue消息池中所有的延遲消息莺掠,并將消息池中所有的非延遲消息派發(fā)出去讓Handler去處理,quitSafely相比于quit方法安全之處在于清空消息之前會派發(fā)所有的非延遲消息读宙。
6, Parcelable 與 Serializable 區(qū)別
兩者最大的區(qū)別在于存儲媒介的不同彻秆,Serializable使用IO讀寫存儲在硬盤上,而Parcelable是直接在內(nèi)存中讀寫结闸,很明顯內(nèi)存的讀寫速度通常大于IO讀寫唇兑,
android上應(yīng)該盡量采用Parcelable,效率至上
編碼上:
Serializable代碼量少桦锄,寫起來方便
Parcelable代碼多一些
效率上:
Parcelable的速度比高十倍以上
serializable的迷人之處在于你只需要對某個類以及它的屬性實現(xiàn)Serializable 接口即可揭措。Serializable 接口是一種標(biāo)識接口(marker interface)濒生,這意味著無需實現(xiàn)方法放仗,Java便會對這個對象進行高效的序列化操作崎脉。
這種方法的缺點是使用了反射,序列化的過程較慢图甜。這種機制會在序列化的時候創(chuàng)建許多的臨時對象碍粥,容易觸發(fā)垃圾回收。
Parcelable方式的實現(xiàn)原理是將一個完整的對象進行分解黑毅,而分解后的每一部分都是Intent所支持的數(shù)據(jù)類型嚼摩,這樣也就實現(xiàn)傳遞對象的功能了
7內(nèi)存抖動;
避免在ondraw()創(chuàng)建對象,因為你會頻繁創(chuàng)建只使用一次的對象低斋,就會導(dǎo)致內(nèi)存的迅速攀升,就很可能觸犯GC的回收匪凡,
這種在短時間內(nèi)反復(fù)發(fā)生內(nèi)存增長和回收的循環(huán)膊畴。有界面卡頓的風(fēng)險。Android 官方叫Memory churn
在onDraw()里創(chuàng)建對象往往跟繪制相關(guān)病游,這些對象又經(jīng)常包含通往系統(tǒng)下層Native的對象引用唇跨,這就導(dǎo)致回收耗時會更高。
8 MVC衬衬、MVP 和 MVVM 區(qū)別
1.1 MVC
1.1.1 MVC三個字母的含義
View :對應(yīng)的XML文件
Model:實體類javabean
Controllor: 對應(yīng)Activity或者Fragment
? 1.1.3 優(yōu)缺點(以android的角度講)
優(yōu)點
Xml就是View層买猖,與java邏輯代碼解耦,具有一定的解耦
缺點
沒有固定的model層滋尉,Activity中代表Controllor玉控,網(wǎng)絡(luò)接口的model也在Activity中,一個邏輯稍微復(fù)雜的頁面代碼行數(shù)都上千行狮惜,影響閱讀高诺,Activity既然控制著View,又含有Model碾篡。相當(dāng)耦合
2.2 MVP
2.2.1 MVP三個字母的含義
View 對應(yīng)于Activity和Xml虱而,負責(zé)頁面的展示
Model 實體類javabean
Presenter 控制器 負責(zé)完成View于Model間的交互與邏輯處理(網(wǎng)絡(luò)和邏輯)
2.2.3 優(yōu)缺點
優(yōu)點:
Model和View之間解耦,兩者交互由Presenter完成开泽,把部分的邏輯的代碼從Fragment和Activity業(yè)務(wù)的邏輯移出來
Activity或者Fragment只是用來展示控件牡拇,或者控制控件的顯示和隱藏,以及View的變化
在MVP中View和presenter要相互持有穆律,方便調(diào)用對方
缺點:
隨著業(yè)務(wù)的增加惠呼,IView的接口和IPresenter的接口會越來越多
更換Xml里面的控件會引起IView接口和IPressenter接口的改動
2.3 MVVM(只從android考慮)
2.3.1 MVVM三個字母的含義
View 還是Activity或者fragment,也就是Xml,負責(zé)頁面的展示,或者控制控件的顯示和隱藏峦耘,以及View的變化罢杉,不參與任何邏輯和數(shù)據(jù)的處理
Viewmodel 主要負責(zé)業(yè)務(wù)邏輯和數(shù)據(jù)處理,本身不持有 View 層引用贡歧,通過LiveData(如果項目中有Rxjava可以不引用LiveData) 向 View 層發(fā)送數(shù)據(jù)滩租,通過DataBinding更改View中的UI層
Model:實體類javabean,便是指這里的Repository ,主要負責(zé)從本地數(shù)據(jù)庫或者遠程服務(wù)器來獲取數(shù)據(jù),Repository統(tǒng)一了數(shù)據(jù)的入口,獲取到數(shù)據(jù),將數(shù)據(jù)發(fā)送?
2.3.3 優(yōu)缺點
優(yōu)點 :
View和數(shù)據(jù)雙向綁定利朵,當(dāng)model變化時會自動同步給View
crash會降低律想,xml里面自己會有判斷
View(Activity或者Fragment)層就是View層,不處理任何關(guān)于數(shù)據(jù)的邏輯
缺點 :
Xml里面寫代碼绍弟,對于android有點不習(xí)慣技即,并且會使xml臃腫
無法快速定位crash位置,Debug比較困難
雙向綁定不利于View的復(fù)用樟遣,因為每個xml里面都有一個model而叼,但是每個頁面的mode有可能不一樣
xml里面寫java代碼身笤,不能用kotlin的簡單語言
UI線程是不安全
悲觀鎖:
Binder 是基于文件的通信方式
RxJava
dispatch Touch Event? 事件分發(fā)
On Intercept? touch Event 是否攔截
On Touch Event? 消耗
ViewGroup和View 的dispatchTouchEvent 是做事件分發(fā),那么這個事件可能分發(fā)出去的四個目標(biāo)
注:------> 后面代表事件目標(biāo)需要怎么做葵陵。
1液荸、 自己消費,終結(jié)傳遞脱篙。------->return true 娇钱;
2、 給自己的onTouchEvent處理-------> 調(diào)用super.dispatchTouchEvent()系統(tǒng)默認會去調(diào)用 onInterceptTouchEvent绊困,在onInterceptTouchEvent return true就會去把事件分給自己的onTouchEvent處理文搂。
3、 傳給子View------>調(diào)用super.dispatchTouchEvent()默認實現(xiàn)會去調(diào)用 onInterceptTouchEvent 在onInterceptTouchEvent return false秤朗,就會把事件傳給子類煤蹭。
4、 不傳給子View取视,事件終止往下傳遞疯兼,事件開始回溯,從父View的onTouchEvent開始事件從下到上回歸執(zhí)行每個控件的onTouchEvent------->return false贫途;
注:?由于View沒有子View所以不需要onInterceptTouchEvent 來控件是否把事件傳遞給子View還是攔截吧彪,所以View的事件分發(fā)調(diào)用super.dispatchTouchEvent()的時候默認把事件傳給自己的onTouchEvent處理(相當(dāng)于攔截),對比ViewGroup的dispatchTouchEvent 事件分發(fā)丢早,View的事件分發(fā)沒有上面提到的4個目標(biāo)的第3點姨裸。
ViewGroup和View的onTouchEvent方法是做事件處理的,那么這個事件只能有兩個處理方式:
1怨酝、自己消費掉傀缩,事件終結(jié),不再傳給誰----->return true;
2农猬、繼續(xù)從下往上傳赡艰,不消費事件,讓父View也能收到到這個事件----->return false;View的默認實現(xiàn)是不消費的斤葱。所以super==false慷垮。
ViewGroup的onInterceptTouchEvent方法對于事件有兩種情況:
1、攔截下來揍堕,給自己的onTouchEvent處理--->return true;
2料身、不攔截,把事件往下傳給子View---->return false,ViewGroup默認是不攔截的衩茸,所以super==false芹血;