Handler
機制隨處可見.Handle異步消息傳遞機制
。UI線程,程序啓動時自動建立。
開發者本身開啓的線程,執行耗時操做等。
UI線程與子線程通訊的媒介,添加消息到消息隊列(Message Queue)處理循環器分發過來的消息(Looper)。
Handler接受&處理的對象,存儲須要操做的消息。
數據存儲結構,採用先進先出方式,存儲Handler發過來的消息。
消息隊列與處理者的媒介,從消息隊列中循環取出消息併發送給Handler處理。
使用Handler.sendMessage()、使用Handler.post()
/** * 方式1:新建Handler子類(內部類) */ // 步驟1:自定義Handler子類(繼承Handler類) & 複寫handleMessage()方法 class mHandler extends Handler { // 經過複寫handlerMessage() 從而肯定更新UI的操做 @Override public void handleMessage(Message msg) { ...// 執行UI操做 } } // 步驟2:在主線程中建立Handler實例 private Handler mhandler = new mHandler(); // 步驟3:建立所需的消息對象 Message msg = Message.obtain(); // 實例化消息對象 msg.what = 1; // 消息標識 msg.obj = "AA"; // 消息內容存放 // 步驟4:在工做線程中 經過Handler發送消息到消息隊列中 mHandler.sendMessage(msg); /** * 方式2:匿名內部類 */ // 步驟1:在主線程中 經過匿名內部類 建立Handler類對象 private Handler mhandler = new Handler(){ // 經過複寫handlerMessage() @Override public void handleMessage(Message msg) { ...// 需執行UI操做 } }; // 步驟2:建立消息對象 Message msg = Message.obtain(); // 實例化消息對象 msg.what = 1; // 消息標識 msg.obj = "AA"; // 消息內容存放 // 步驟3:在工做線程中 經過Handler發送消息到消息隊列中 mHandler.sendMessage(msg);
new Thread() { @Override public void run() { try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } // 經過psot()發送,傳入1個Runnable對象 mHandler.post(new Runnable() { @Override public void run() { // 指定操做UI內容 } }); } }.start();
在源碼分析前,先來了解Handler機制中的幾個核心類android
關於這幾個類的具體做用前面已經介紹過了就再也不過多闡述了。segmentfault
下面開始源碼分析,注意力集中了
上文中咱們提到過Handler發送消息有兩種方式,分別是安全
下面先從第一種開始分析:多線程
//經過匿名內部類 建立Handler類對象 private Handler mhandler = new Handler(){ // 經過複寫handlerMessage()從而肯定更新UI的操做 @Override public void handleMessage(Message msg) { ...// 需執行的UI操做 } }; ---------->>開始源碼分析 public Handler() { this(null, false); // ->>此處this指代的就是當前的Handler實例,調用有參構造 } public Handler(Callback callback, boolean async) { ...// 無關代碼我就不貼了 // 1. 指定Looper對象 mLooper = Looper.myLooper(); if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); } // Looper.myLooper()做用:獲取當前線程的Looper對象;若線程無Looper對象則拋出異常 // 可經過執行Loop.getMainLooper()方法得到主線程的Looper對象 // 2. 綁定消息隊列對象(MessageQueue) mQueue = mLooper.mQueue; // 獲取該Looper對象中保存的消息隊列對象(MessageQueue) // 至此,完成了handler 與 Looper對象中MessageQueue的關聯 }
public static void main(String[] args) { ... // 無關的代碼 Looper.prepareMainLooper(); // 1. 爲主線程建立1個Looper對象,同時生成1個消息隊列對象(MessageQueue) ActivityThread thread = new ActivityThread(); // 2. 建立主線程 Looper.loop(); // 3. 自動開啓 消息循環 }
public void dispatchMessage(Message msg) { // 1. 若msg.callback屬性不爲空,則表明使用了post(Runnable r)發送消息 // 則執行handleCallback(msg),即回調Runnable對象裏複寫的run() if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } // 2. 若msg.callback屬性爲空,則表明使用了sendMessage(Message msg)發送消息,即回調複寫的handleMessage(msg) handleMessage(msg); } } public void handleMessage(Message msg) { ... // 建立Handler實例時複寫 }
從以上源碼來看,使用Handler.post()時,系統會自動回調Runnable對象裏複寫的run()方法,將其打包成msg對象, 實際上和sendMessage(Message msg)發送方式相同。併發
至此,關於Handler的異步消息傳遞機制的解析就完成了。
1.Handler的通常用法 : 新建Handler子類(內部類) 、匿名Handler內部類,而在咱們編寫代碼的時候,其實編譯器就會提示咱們這種操做可能會發生內存泄漏,在android studio中就是這塊代碼會變黃。
2.提示的緣由是異步
3.內存泄漏的緣由
首先咱們先要了解一些其餘的知識點。async
而在Handler處理消息的時候,Handler必須處理完全部消息纔會與外部類解除引用關係,若是此時外部Activity須要提早被銷燬了,而Handler因還未完成消息處理而繼續持有外部Activity的引用。因爲上述引用關係,垃圾回收器(GC)便沒法回收MainActivity,從而形成內存泄漏。ide
將Handler的子類設置成 靜態內部類,同時,還可加上 使用WeakReference弱引用持有Activity實例。
緣由:弱引用的對象擁有短暫的生命週期。在垃圾回收器線程掃描時,一旦發現了只具備弱引用的對象,無論當前內存空間足夠與否,都會回收它的內存。oop
// 設置爲:靜態內部類 private static class FHandler extends Handler{ // 定義 弱引用實例 private WeakReference<Activity> reference; // 在構造方法中傳入需持有的Activity實例 public FHandler(Activity activity) { // 使用WeakReference弱引用持有Activity實例 reference = new WeakReference<Activity>(activity); } // 複寫handlerMessage() @Override public void handleMessage(Message msg) { switch (msg.what) { case 1: //更新UI break; case 2: //更新UI break; }
@Override protected void onDestroy() { super.onDestroy(); mHandler.removeCallbacksAndMessages(null); // 外部類Activity生命週期結束時,同時清空消息隊列 & 結束Handler生命週期 }
推薦使用上述解決方法一,以保證保證Handler中消息隊列中的全部消息都能被執行
本文主要講述了Handler的基本原理和使用方法,以及形成內存泄漏的緣由和解決方案。源碼分析
歡迎關注做者darryrzhong,更多幹貨等你來拿喲.
更多精彩文章請關注