Android Handler

    當咱們建立的Service、Activity以及Broadcast均是一個主線程處理,這裏咱們能夠理解爲UI線程。可是在操做一些耗時操做時,好比I/O讀寫的大文件讀寫,數據庫操做以及網絡下載須要很長時間,爲了避免阻塞用戶界面,出現ANR的響應提示窗口,這個時候咱們能夠考慮使用Thread線程來解決。    java

    不少初入Android或Java開發的新手對Thread、Looper、Handler和Message仍然比較迷惑,衍生的有HandlerThread、java.util.concurrent、Task、AsyncTask也是隻知其一;不知其二。android

Handler簡單的總結:

一. postInvalidate()

    以使用postInvalidate()方法在線程中來處理在線程中的刷新一個View爲基類的界面,其中還提供了一些重寫方法好比postInvalidate(int left,int top,int right,int bottom) 來刷新一個矩形區域,以及延時執行,好比postInvalidateDelayed(long delayMilliseconds)或postInvalidateDelayed(long delayMilliseconds,int left,int top,int right,int bottom) 方法,其中第一個參數爲毫秒程序員

二.Handler

     固然推薦的方法是經過一個Handler來處理這些,能夠在一個線程的run方法中調用handler對象的 postMessage或sendMessage方法來實現,Android程序內部維護着一個消息隊列,會輪訓處理這些,若是你是Win32程序員能夠很好理解這些消息處理,不過相對於Android來講沒有提供 PreTranslateMessage這些干涉內部的方法。數據庫

    使用Handler以前,咱們都是初始化一個實例,好比用於更新UI線程,咱們會在聲明的時候直接初始化,或者在onCreate中初始化Handler實例。網絡

    Handler的構造方法異步

    看其如何與MessageQueue聯繫上的,它在子線程中發送的消息(通常發送消息都在非UI線程)怎麼發送到MessageQueue中的。async

public Handler() {  
    this(null, false);  
} 
 
public Handler(Callback callback, boolean async) {  
    if (FIND_POTENTIAL_LEAKS) {  
        final Class<? extends Handler> klass = getClass();  
        if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) 
                && (klass.getModifiers() & Modifier.STATIC) == 0) {  
            Log.w(TAG, "The following Handler class should be static or leaks might occur: "
                 + klass.getCanonicalName());  
        }  
    }  
    mLooper = Looper.myLooper();  //獲取當前線程保存的Looper實例,
                                  //保證了handler的實例與咱們Looper實例中MessageQueue關聯上了。
    if (mLooper == null) {  
        throw new RuntimeException("Can't create handler inside thread that has not 
            called Looper.prepare()");  
    }  
    mQueue = mLooper.mQueue;  //獲取這個Looper實例中保存的MessageQueue(消息隊列)
    mCallback = callback;  
    mAsynchronous = async;  
}

    查看sendMessage方法源碼發現ide

    1.sendMessage()->sendMessageDelayed();  函數

    2.sendEmptyMessageDelayed()->sendMessageDelayed();oop

    3.sendMessageDelayed()->sendMessageAtTime();

    1/2/3展轉反則最後調用了sendMessageAtTime(),sendMessageAtTime()內部有直接獲取MessageQueue而後調用了enqueueMessage方法,咱們再來看看此方法:

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {  
   msg.target = this;  
   if (mAsynchronous) {  
       msg.setAsynchronous(true);  
   }  
   return queue.enqueueMessage(msg, uptimeMillis);  
}

    enqueueMessage中首先爲meg.target賦值爲this,【若是你們還記得Looper的loop方法會取出每一個msg而後交給msg,target.dispatchMessage(msg)去處理消息】,也就是把當前的handler做爲msg的target屬性。最終會調用queue的enqueueMessage的方法,也就是說handler發出的消息,最終會保存到消息隊列中去。

    如今已經很清楚了Looper會調用prepare()和loop()方法,在當前執行的線程中保存一個Looper實例,這個實例會保存一個MessageQueue對象,而後當前線程進入一個無限循環中去,不斷從MessageQueue中讀取Handler發來的消息。而後再回調建立這個消息的handler中的dispathMessage方法,下面咱們趕快去看一看這個方法:

public void dispatchMessage(Message msg) {  
    if (msg.callback != null) {  
        handleCallback(msg);  //這是一個空方法,由於消息的最終回調是由咱們控制的,
                    //咱們在建立handler的時候都是複寫handleMessage方法,而後根據msg.what進行消息處理。
    } else {  
        if (mCallback != null) {  
            if (mCallback.handleMessage(msg)) {  
                return;  
            }  
        }  
        handleMessage(msg);  
    }  
}

    Handler 建立實例:

private Handler mHandler = new Handler(){  
    //複寫handleMessage方法
    public void handleMessage(android.os.Message msg){  
        switch (msg.what) {  
        case value:  
            break;  
        default:  
            break;  
        }  
    };  
};

 

三. Looper    

    其實Android中每個Thread都跟着一個Looper,Looper能夠幫助Thread維護一個消息隊列,可是Looper和Handler沒有什麼關係,咱們從開源的代碼能夠看到Android還提供了一個Thread繼承類HanderThread能夠幫助咱們處理,在HandlerThread對象中能夠經過getLooper方法獲取一個Looper對象控制句柄,咱們能夠將其這個Looper對象映射到一個Handler中去來實現一個線程同步機制,Looper對象的執行須要初始化Looper.prepare方法同時推出時還要釋放資源,使用Looper.release方法。應用程序的主線程中會始終存在一個Looper對象,在主線程中能夠直接建立Handler對象,而在子線程中須要先調用Looper.prepare()才能建立Handler對象。

 

    Android Looper簡介

四.Message    

對於Android中Handler能夠傳遞一些內容,經過Bundle對象能夠封裝String、Integer以及Blob二進制對象,咱們經過在線程中使用Handler對象的sendEmptyMessage或sendMessage方法來傳遞一個Bundle對象到Handler處理器。對於Handler類提供了重寫方法handleMessage(Message msg) 來判斷,經過msg.what來區分每條信息。將Bundle解包來實現Handler類更新UI線程中的內容實現控件的刷新操做。相關的Handler對象有關消息發送sendXXXX相關方法以下,同時還有postXXXX相關方法,這些和Win32中的道理基本一致,一個爲發送後直接返回,一個爲處理後才返回 .

五. java.util.concurrent對象分析

對於過去從事Java開發的程序員不會對Concurrent對象感到陌生吧,他是JDK 1.5之後新增的重要特性做爲掌上設備,咱們不提倡使用該類,考慮到Android爲咱們已經設計好的Task機制,這裏不作過多的贅述,相關緣由參考下面的介紹:

六. AsyncTask:

在Android中還提供了一種有別於線程的處理方式,就是Task以及AsyncTask,從開源代碼中能夠看到是針對Concurrent的封裝,開發人員能夠方便的處理這些異步任務。

 Android AsyncTask

七.Handler發送消息:

        new出一個Message對象,而後可使用setData()方法或arg參數等方式爲消息攜帶一些數據,再借助Handler將消息發送出去就能夠了。

new Thread(new Runnable() {  
    @Override  
    public void run() {  
        Message message = new Message();  
        message.arg1 = 1;  
        Bundle bundle = new Bundle();  
        bundle.putString("data", "data");  
        message.setData(bundle);  
        handler.sendMessage(message);  
    }  
}).start();

        Handler中提供了不少個發送消息的方法,其中除了sendMessageAtFrontOfQueue()方法以外,其它的發送消息方法最終都會展轉調用到sendMessageAtTime()方法中。

        sendMessageAtTime()方法接收兩個參數,其中msg參數就是咱們發送的Message對象,而uptimeMillis參數則表示發送消息的時間,它的值等於自系統開機到當前時間的毫秒數再加上延遲時間,若是你調用的不是sendMessageDelayed()方法,延遲時間就爲0,而後將這兩個參數都傳遞到MessageQueue的enqueueMessage()方法中。

八.MessageQueue  

   它是一個消息隊列,用於將全部收到的消息以隊列的形式進行排列,並提供入隊和出隊的方法。這個類是在Looper的構造函數中建立的,所以一個Looper也就對應了一個MessageQueue。

    MessageQueue並無使用一個集合把全部的消息都保存起來,它只使用了一個mMessages對象表示當前待處理的消息。MessageQueue的對象調用enqueueMessage(msg, uptimeMillis)方法將消息加入到消息隊列,返回bool類型的值。所謂的入隊其實就是將全部的消息按時間來進行排序,這個時間是sendMessageAtTime(Message msg, long uptimeMillis)中的uptimeMillis參數。具體的操做方法就根據時間的順序調用msg.next,從而爲每個消息指定它的下一個消息是什麼。固然若是你是經過sendMessageAtFrontOfQueue()方法來發送消息的,它也會調用enqueueMessage()來讓消息入隊,只不過期間爲0,這時會把mMessages賦值爲新入隊的這條消息,而後將這條消息的next指定爲剛纔的mMessages,這樣也就完成了添加消息到隊列頭部的操做。

九.除了發送消息以外,咱們還有如下幾種方法能夠在子線程中進行UI操做:

    1. Handler的post()方法

    2. View的post()方法,就是調用了Handler中的post()方法

    3.Activity的runOnUiThread()方法

    Android 子線程中進行UI操做(非發送消息)

十.Handler 、 Looper 、Message之間的關係:

    其實Looper負責的就是建立一個MessageQueue,而後進入一個無限循環體不斷從該MessageQueue中讀取消息,而消息的建立者就是一個或多個Handler 。

    一、首先Looper.prepare()在本線程中保存一個Looper實例,而後該實例中保存一個MessageQueue對象;由於Looper.prepare()在一個線程中只能調用一次,因此MessageQueue在一個線程中只會存在一個。

    二、Looper.loop()會讓當前線程進入一個無限循環,不端從MessageQueue的實例中讀取消息,而後回調msg.target.dispatchMessage(msg)方法。

    三、Handler的構造方法,會首先獲得當前線程中保存的Looper實例,進而與Looper實例中的MessageQueue想關聯。

    四、Handler的sendMessage方法,會給msg的target賦值爲handler自身,而後加入MessageQueue中。

    五、在構造Handler實例時,咱們會重寫handleMessage方法,也就是msg.target.dispatchMessage(msg)最終調用的方法。

十一.Handler的post方法建立的線程和UI線程之間的關係:

mHandler.post(new Runnable() {  
    @Override  
    public void run()  {  
        Log.e("TAG", Thread.currentThread().getName());  
        mTxt.setText("yoxi");  
    }  
});

    而後run方法中能夠寫更新UI的代碼,其實這個Runnable並無建立什麼線程,而是發送了一條消息,下面看源碼:

public final boolean post(Runnable r)  {  
  return  sendMessageDelayed(getPostMessage(r), 0);  
}  
private static Message getPostMessage(Runnable r) {  
  Message m = Message.obtain();  
  m.callback = r;  
  return m;  
}

    能夠看到,在getPostMessage中,獲得了一個Message對象,而後將咱們建立的Runable對象做爲callback屬性,賦值給了此message.

    注:產生一個Message對象,能夠new  ,也可使用Message.obtain()方法;二者均可以,可是更建議使用obtain方法,由於Message內部維護了一個Message池用於Message的複用,避免使用new 從新分配內存。

public final boolean sendMessageDelayed(Message msg, long delayMillis){  
    if (delayMillis < 0) {  
        delayMillis = 0;  
    }  
    return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);  
}

 

public boolean sendMessageAtTime(Message msg, long uptimeMillis) {  
    MessageQueue queue = mQueue;  
    if (queue == null) {  
        RuntimeException e = new RuntimeException(this + " sendMessageAtTime() called with no mQueue");  
        Log.w("Looper", e.getMessage(), e);  
        return false;  
    }  
    return enqueueMessage(queue, msg, uptimeMillis);  
}

    最終和handler.sendMessage同樣,調用了sendMessageAtTime,而後調用了enqueueMessage方法,給msg.target賦值爲handler,最終加入MessagQueue.

    能夠看到,這裏msg的callback和target都有值,可是執行dispatchMessage方法:

public void dispatchMessage(Message msg) {  
    if (msg.callback != null) {  //若是不爲null,則執行callback回調,也就是咱們的Runnable對象。
        handleCallback(msg);  
    } else {  
        if (mCallback != null) {  
            if (mCallback.handleMessage(msg)) {  
                return;  
            }  
        }  
        handleMessage(msg);  
    }  
}

十二.Handler中obtainMessage與new Message的區別:

在handler.obtainMessage()的參數是這樣寫的:

Message android.os.Handler.obtainMessage(int what, int arg1, int arg2, Object obj)
Parameters
what  Value to assign to the returned Message.what field.
arg1  Value to assign to the returned Message.arg1 field.
arg2  Value to assign to the returned Message.arg2 field.
obj  Value to assign to the returned Message.obj field.

obtainmessage()是從消息池中拿來一個msg 不須要另開闢空間。

new須要從新申請,效率低,obtianmessage能夠循環利用;

obtainMessage寫法:

1.mHandler.obtainMessage(what, arg1, 0, object).sendToTarget();
2.Message msg = mHandler.obtainMessage();
  msg.what = what;
  msg.obj = object;
  msg.sendToTarget();

message 從handler 類獲取,從而能夠直接向該handler 對象發送消息。

New Message寫法:

Message msg=new Message();  
msg.arg1=i;  
handler.sendMessage(msg);

直接調用 handler 的發送消息方法發送消息。

兩種寫法中Message都可以setData(Bundle bundle)

相關文章
相關標籤/搜索