這篇帶你搞懂Handler怎麼線程間通信的

一直對handler似懂非懂,這次看了別的文章加上自己的理解,終於明白Handler到底是如何實現線程間的通信了.大家共同探討研究.
首先得明白,一個線程只有一個Looper和MessageQueue.調用本線程的Handler只能發送Message到本線程的MessageQueue.那怎麼區分Handler是哪個線程的呢,是通過Handler對象中的Looper對象.然後本線程Looper對象loop(),不斷從MessageQueue取消息.

1.主線程初始化Handler

//內存泄漏的問題請先忽略
 private Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what){
                ...
            }
        }
    };

直接新建一個Handler,它是主線程的.答案在源碼.看下面.

//Handler源碼片段
if (FIND_POTENTIAL_LEAKS) {
            final Class<? extends Handler> klass = getClass();
   ...

        mLooper = Looper.myLooper(); //注意這句
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread " + Thread.currentThread()
                        + " that has not called Looper.prepare()");
        }
    ...

mLooper = Looper.myLooper(); 這句代碼獲取的是主線程的Looper,而它在ActivityThread中已經初始化過了,這裏不多說.

2.子線程發消息給主線程

a.在子線程裏發送消息

private void childThreadSendMessageToMain() {
        new Thread(){
            @Override
            public void run() {
                super.run();
                Message message = handler.obtainMessage();
                message.what = mess_thread1;
                message.obj = "我是子線程1發來的消息";
                handler.sendMessage(message); //注意這句
            }
        }.start();

    }

handler.sendMessage(message); 這裏的handler是我們上面在主線程初始化的,是主線程的Handler,這樣在主線程的handleMessage()中就可以收到子線程發來的Message

a.在主線程接收消息

public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what){
                //注意這裏
                case mess_thread1:
                    Log.d(TAG, "handleMessage: 接收到來自mess_thread1的消息");
                    Log.d(TAG, "handleMessage: msg.obj=" + msg.obj);
                ...
            }
        }

c.結果打印

D/ScrollingActivity: handleMessage: 接收到來自mess_thread1的消息
D/ScrollingActivity: handleMessage: msg.obj=我是子線程1發來的消息

2.主線程發消息給子線程

這裏有個問題,當我在主線程使用子線程Handler時,子線程的Handler沒有初始化好怎麼辦?我們這樣解決:
首先: 子線程裏初始化Handler
再次: 子線程發送給主線程消息: 子線程的Handler準備好了
再次: 主線程使用子線程的Handler發送消息
最後: 子線程接收並處理主線程發送過來的消息

a.我們改變寫法,在主線程寫一個類繼承自Handler

private class ChildHandler extends Handler{
        //參數爲looper,到時候傳入一個子線程的looper,這個handler就成了子線程的了
        private ChildHandler(Looper looper){
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what){
                ...
            }
        }
    }

b.開始在子線程new Handler,並且發送消息

private void initChildHandler(){
        new Thread(){
            @Override
            public void run() {
                Looper.prepare();
                childThreadHandler = new ChildHandler(Looper.myLooper());
                Message message = handler.obtainMessage();
                message.what = child_handler_ok;
                message.obj = "子線程handler準備好了";
                handler.sendMessage(message);
                Looper.loop();

            }
        }.start();
    }

b.主線程接收"子線程handler準備好"的消息,並使用子線程的Handler給子線程發消息

//接收處理子線程handler準備好的消息
private Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what){
                case child_handler_ok:
                    Log.d(TAG, "handleMessage: 接收到子線程消息");
                    Log.d(TAG, "handleMessage: msg.obj=" + msg.obj);
                    sendMessageToChildThread();
                    break;
            }
        }
    };

c.主線程發消息給子線程

//使用子線程handler發送消息到子線程
    private void sendMessageToChildThread() {
        Message message = childThreadHandler.obtainMessage();
        message.what = mess_mainThread;
        message.obj = "我是主線程,已收到子線程handler準備好的消息";
        childThreadHandler.sendMessage(message);
    }

d.結果打印

handleMessage: child_handler_ok
handleMessage: msg.obj=子線程handler準備好了
handleMessage: mess_mainThread
handleMessage: msg.obj=我是主線程,已收到子線程handler準備好的消息

3.子線程發消息給子線程

a.接着上面,我們再新建一個線程,稱之爲子線程2,原來的子線程稱之爲子線程1,

//在子線程2中使用子線程1的handler發送消息,實現了子線程之間的通信
  private void initChild2Thread() {
        new Thread(){
            @Override
            public void run() {
                Message message = childThreadHandler.obtainMessage();
                message.what = child2_thread;
                message.obj = "我是另一個子線程發送的消息";
                childThreadHandler.sendMessage(message);
            }
        }.start();
    }

b.我們在子線程1中接收

//這裏說明一下,由於new的時候我們傳入了子線程1的looper,所以這個handler屬於子線程1
private class ChildHandler extends Handler{
        private ChildHandler(Looper looper){
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what){
             ...
                case child2_thread:
                    Log.d(TAG, "handleMessage: child2_thread" );
                    Log.d(TAG, "handleMessage: msg.obj=" + msg.obj);
                    break;
            }
        }
    }

c.結果打印

D/ScrollingActivity: handleMessage: child2_thread
D/ScrollingActivity: handleMessage: msg.obj=我是另一個子線程發送的消息

4.總結

想給哪個線程發消息,就使用目標線程的Handler,而區別Hander是哪個線程的,就是Handl持有哪個線程的Looper.

Android架構資源:在此處觀看

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章