異步消息處理機(jī)制相關(guān)面試題

一.Handler的四大組件和運(yùn)作機(jī)制

? ? handler其實就是androidSDK提供給我們開發(fā)者方便進(jìn)行異步消息處理的類

? ? 例如,asynctask,retrofit都是封裝了handler


? ? 注意:

????1.每一給線程只能有一個looper,主線程中創(chuàng)建looper,并且在looper內(nèi)創(chuàng)建messagequeue

? ? 2.Looper類主要是為每個線程開啟的單獨的消息循環(huán)

? ? 3.messagequeue通過looper來管理message

? ? 4.messagequeue利用先進(jìn)先出的原理來處理message

? ? 5.handler的作用就是發(fā)送消息和處理消息

? ? 6.handler是looper的一個接口

? ? 7.在非主線程中直接new Handler是不可以,除非先創(chuàng)建Looper的對象

整體流程:創(chuàng)建handler的時候回獲取到當(dāng)前線程的looper,然后通過這個looper獲取到這個消息隊列meessagequeue,然后通過handler來發(fā)送消息message,將message發(fā)送到消息隊列messagequeue,然后再通過looper輪詢消息隊列取出消息再交給handler處理,這個時候再handler里面的handlermessage方法

? ? ?1>在什么情況下使用handler會造成內(nèi)存泄露

private Handler handler =new Handler(){

? ? ? public void handleMessage(android.os.Message msg){

????????????if(msg.what == 1){? ? ? ? ? ? ? ?

?????????????????noteBookAdapter.notifyDataSetChanged();? ? ? ? ? ??

?????????????}? ? ? ??

????}?

};

上面是一段簡單的Handler的使用。當(dāng)使用內(nèi)部類(包括匿名類)來創(chuàng)建Handler的時候,Handler對象會隱式地持有一個外部類對象(通常是一個Activity)的引用(不然你怎么可能通過Handler來操作Activity中的View?)。而Handler通常會伴隨著一個耗時的后臺線程(例如從網(wǎng)絡(luò)拉取圖片)一起出現(xiàn),這個后臺線程在任務(wù)執(zhí)行完畢(例如圖片下載完畢)之后,通過消息機(jī)制通知Handler,然后Handler把圖片更新到界面。然而,如果用戶在網(wǎng)絡(luò)請求過程中關(guān)閉了Activity,正常情況下,Activity不再被使用,它就有可能在GC檢查時被回收掉,但由于這時線程尚未執(zhí)行完,而該線程持有Handler的引用(不然它怎么發(fā)消息給Handler?),這個Handler又持有Activity的引用,就導(dǎo)致該Activity無法被回收(即內(nèi)存泄露),直到網(wǎng)絡(luò)請求結(jié)束(例如圖片下載完畢)。另外,如果你執(zhí)行了Handler的postDelayed()方法,該方法會將你的Handler裝入一個Message,并把這條Message推到MessageQueue中,那么在你設(shè)定的delay到達(dá)之前,會有一條MessageQueue -> Message -> Handler -> Activity的鏈,導(dǎo)致你的Activity被持有引用而無法被回收。

? ? 2>如何解決因為handler所引起的內(nèi)存泄露

方法一:通過程序邏輯來進(jìn)行保護(hù)。

1.在關(guān)閉Activity的時候停掉你的后臺線程。線程停掉了,就相當(dāng)于切斷了Handler和外部連接的線,Activity自然會在合適的時候被回收。?

2.如果你的Handler是被delay的Message持有了引用,那么使用相應(yīng)的Handler的removeCallbacks()方法,把消息對象從消息隊列移除就行了。

方法二:將Handler聲明為靜態(tài)類。

在Java 中,非靜態(tài)的內(nèi)部類和匿名內(nèi)部類都會隱式地持有其外部類的引用,靜態(tài)的內(nèi)部類不會持有外部類的引用。

靜態(tài)類不持有外部類的對象,所以你的Activity可以隨意被回收。由于Handler不再持有外部類對象的引用,導(dǎo)致程序不允許你在Handler中操作Activity中的對象了。所以你需要在Handler中增加一個對Activity的弱引用(WeakReference)。

二.AsyncTask

? ? 1.Handler+線程池的封裝

? ? ? ? 1>onPreExecute()----->運(yùn)行在UI線程中,在調(diào)用DoInBackground()之前執(zhí)行,可以做初始化操作

? ? ? ? 2>doInbackground()----->后臺運(yùn)行,非UI線程,可以執(zhí)行耗時方法

? ? ? ? 3>onPostExecute()------>運(yùn)行在UI線程中,在doinbackground()執(zhí)行完畢后執(zhí)行

? ? ? ? 4>onProgressUpdate()----->在publishProgress()被調(diào)用后執(zhí)行,publishProgress()用于更新進(jìn)度,在UI線程中執(zhí)行

? ? 注意要點:

? ? ? ? ? 1>AsyncTask的實例必須在主線程中創(chuàng)建

? ? ? ? ? ?2>AsyncTask的excute方法必須在主線程中調(diào)用

? ? ? ? ? ? 3>回調(diào)方法,android會自動調(diào)用

? ? ? ? ? ? 4>一個AsyncTack的實例,只能執(zhí)行一次execute方法

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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