一.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方法