android 的訊息處理

來源:互聯網
上載者:User

標籤:

算是工作記錄吧。。。

首先,android中介面的更新都必須放到主線程中間去做,當我們在子線程中想要更新介面的時候,可以通過Handler和Message這兩個類來進行處理。比如新開了一個線程,用來進行下載任務,通過Handler顯示進度條等。大概的過程是這樣的,首先獲得一個message ,然後調用sendMessage發送出去,然後就可以在重寫的handler類的函數裡面進行處理了。

new Thread() {            public void run() {                    ...                Message msg = Message.obtain();                ...                msg.what = NETWORK_ERROR; 
         ...
         handler.sendMessage(msg);
        }
}.start();
private Handler handler = new Handler() {        public void handleMessage(android.os.Message msg) {            switch (msg.what) {            case NETWORK_ERROR:                ...                break;            }        };    };

我們可以點進去看看Handler和Message的源碼,會發現內部還會涉及到兩個類,Looper和MessageQueue。

先看Message,

public final class Message implements Parcelable {    public int what;    public int arg1;     public int arg2;    public Object obj;    public Messenger replyTo;    /*package*/ int flags;    /*package*/ long when;        /*package*/ Bundle data;        /*package*/ Handler target;             /*package*/ Runnable callback;           /*package*/ Message next;    ...}

然後首先的問題是,為什麼不直接Message msg = new Message(),而是用Message.obtain() ;這點在注釋裡已經有說明了:

    /**     * Return a new Message instance from the global pool. Allows us to     * avoid allocating new objects in many cases.     */    public static Message obtain() {        synchronized (sPoolSync) {            if (sPool != null) {                Message m = sPool;                sPool = m.next;                m.next = null;                sPoolSize--;                return m;            }        }        return new Message();    } public static Message obtain(Handler h, Runnable callback); public static Message obtain(Handler h, int what)
  ...

 

這裡採用類似於線程池的方法,是從global pool裡面取出來訊息,當global pool中的訊息全部被用光了,才會new Message(),避免頻繁申請和釋放資源帶來的效能損耗。這個類下面也寫了很多個不同參數的重載方法。另外一種獲得Message的方法是Handler.obtainMessage(),看源碼可以知道也是調用的Message.obtain();

然後是發送訊息的方式,handler.sendMessage :

public void sendToTarget() {    target.sendMessage(this);}

 這裡的target在上面可以看到,是Message的一個Handler類型的成員,表示接收這個訊息的handler對象。而Handler類裡面的sendMessage方法,一路跟下去可以看到,最後執行的是調用Handler類的MessageQueue類成員對象mQueue的enqueueMessage方法。

   public final boolean sendMessage(Message msg)    {        return sendMessageDelayed(msg, 0);    }         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);    }    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {        msg.target = this;        if (mAsynchronous) {            msg.setAsynchronous(true);        }        return queue.enqueueMessage(msg, uptimeMillis);    }

因此sendMessage ,實際上是發送到Message對象的handler成員的MessageQueue隊列裡面去了。然後的問題是訊息是怎麼取出來的?先看Handler類:

public class Handler {    final MessageQueue mQueue;    final Looper mLooper;    final Callback mCallback;    final boolean mAsynchronous;    IMessenger mMessenger;        /**     * Default constructor associates this handler with the {@link Looper} for the     * current thread.     *     * If this thread does not have a looper, this handler won‘t be able to receive messages     * so an exception is thrown.     */    public Handler() {        this(null, false);    }          public Handler(Callback callback, boolean async) {        ...        mLooper = Looper.myLooper();        if (mLooper == null) {            throw new RuntimeException(                "Can‘t create handler inside thread that has not called Looper.prepare()");        }        mQueue = mLooper.mQueue;        mCallback = callback;        mAsynchronous = async;    }   
  ... }

 

 

可以看到,handler建立的時候沒有指定Looper的話,是會預設綁定到當前的線程中去的。當我們在Activity中直接new Handler的時候,就綁定到主線程上面去了。

因此整個過程是,當android程式啟動的時候,主線程就會啟動了,然後啟動主線程的訊息迴圈,也就是Looper.loop(),因此預設new Handler出來的對象,都會把訊息發送到主線程的MessageQueue中去。子線程建立的時候不會預設啟動訊息迴圈,想要進行訊息處理,必須主動去啟動訊息迴圈,產生自己的訊息佇列。Looper中的loop方法:

 public static void loop() {        final Looper me = myLooper();    ...        final MessageQueue queue = me.mQueue;        for (;;) {            Message msg = queue.next(); // might block            if (msg == null) {                // No message indicates that the message queue is quitting.                return;            }            msg.target.dispatchMessage(msg);            ...            msg.recycle();        }

 

調用了loop方法以後,就開始執行分發和回收訊息的動作了,Handler.dispatchMessage:

    public void dispatchMessage(Message msg) {        if (msg.callback != null) {            handleCallback(msg);        } else {            if (mCallback != null) {                if (mCallback.handleMessage(msg)) {                    return;                }            }            handleMessage(msg);        }    }

 

首先檢查Message的Runnable介面是否為空白,然後檢查handler的callback是否為空白,如果都是空,進入到Handler的handlerMessage方法,因為多態的原因,最終會跳轉到我們重寫的handlerMessage()方法裡面去!

 

看完之後的感想:既然每一個訊息都有一個handler對象作為target,而我們可以把很多handler都綁定到主線程的訊息佇列裡面去,因此只要獲得了介面A的handler,那麼就可以給介面A發送訊息,進入介面A的訊息處理函數裡面去!是不是有點類似於windows視窗的控制代碼呢,:-),這也是我在後面JNI調用的時候所使用的通知android介面的方法。

 

android 的訊息處理

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.