1. Handler使用示例

public class DownloadActivity extends AppCompatActivity implements View.OnClickListener {
    private TextView downloadTV;
    private Button downloadBtn;
    private Handler handler = new Handler() {//主线程创建Handler并复写handleMessage
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            downloadTV.setText("下载完成");
        }
    };
	public void onClick(View v) {
        switch (v.getId()){
            case R.id.download_btn:
                new Thread(new Runnable() {	//子线程使用handler执行sendEmptyMessage发送Message
                    @Override               //消息为空,可以使用Message.what指定消息类型, Message.obj指定消息主体
                    public void run() {
                        try {
                            Thread.sleep(5000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        handler.sendEmptyMessage(1);
                    }
                }).start();
                break;
        }
    }
}

Handler用法总结:
首先定义一个继承自Handler的MyHandler并复写handleMessage方法,主线程实例化MyHandler,子线程调用Handler.sendMessage发送消息,回调主线程的Handler.handleMessage

2. 主线程创建Looper的过程

每个定义了Handler 的线程都必须有一个 Looper ,主线程当然也不例外,上面的示例中Looper如何创建?

android创建一个子线程 android handler两个子线程通信_线程创建


通常认为ActivityThread就是Activity的主线程

分析:Looper.prepareMainLooper();

android创建一个子线程 android handler两个子线程通信_主线程_02


分析:Looper.loop();

android创建一个子线程 android handler两个子线程通信_主线程_03


主线程的Looper创建过程总结:

首先执行Looper.prepare()创建Looper,并创建MessageQueue保存到Looper.mQueue;

然后执行Looper.loop()进入死循环处理消息,取出MessageQueue中的Message,其中msg.target即为Message的发送者Handler,最终调用dispatchMessage回调handleMessage

3. 主线程创建Handler的过程

android创建一个子线程 android handler两个子线程通信_主线程_04


android创建一个子线程 android handler两个子线程通信_线程创建_05


android创建一个子线程 android handler两个子线程通信_主线程_06


主线程创建Handler时,在Handler的构造函数中会取出主线程创建的Looper,并将Looper. mQueue保存到Handler. mQueue,由于主线程只有一个Looper,因此无论主线程创建多少个Handler,其中的messageQueue保存的都是Looper中的MessageQueue

4. 主线程创建Handler的过程

android创建一个子线程 android handler两个子线程通信_Android_07


最终调用到:

android创建一个子线程 android handler两个子线程通信_Handler_08


取出Looper中的MessageQueue

android创建一个子线程 android handler两个子线程通信_Handler_09


将this即调用着Handler保存到message中的target中

android创建一个子线程 android handler两个子线程通信_Android_10


Handler执行sendMessage时会调用enqueueMessage将消息的发送者Handler保存到Message.target,最后将Message放入调用者Handler中的MessageQueue的尾部,由于Handler中的MessageQueue即为Looper中的MessageQueue,所以Handler执行sendMessage时最终将Message保存到Looper中的MessageQueue中

备注:MessageQueue是单向链表形式存在的

5. Looper取出Message交给Handler处理

android创建一个子线程 android handler两个子线程通信_Android_11


android创建一个子线程 android handler两个子线程通信_主线程_12


android创建一个子线程 android handler两个子线程通信_android创建一个子线程_13


执行Looper.loop()会循环从MessageQueue取出Message,从Message.target找出Message的发送者Handler,回调Handler.handleMessage处理消息

6. MessageQueue为空会怎么样

a. MessageQueue为空时休眠

android创建一个子线程 android handler两个子线程通信_线程创建_14


在执行Looper.loop()的过程中会执行Message msg = queue.next();当MessageQueue为空时会导致nextPollTimeoutMillis = -1;当下一次for循环执行nativePollOnce时,最后会执行nativePollOnce,通过jni调用pollOnce

android创建一个子线程 android handler两个子线程通信_android创建一个子线程_15


当传入参数nextPollTimeoutMillis = -1,执行epoll_wait时会休眠可以看到这里使用到了Linux的epoll机制

epoll机制:

android创建一个子线程 android handler两个子线程通信_Android_16


b. 下一次王MessageQueue放入Message时解除休眠

在Looper构造函数中执行:

android创建一个子线程 android handler两个子线程通信_Android_17


可以看到当执行epoll_wait的时候会检测mWakeReadPipeFd和mWakeWritePipeFd两个文件句柄的值,当着两个句柄有数据时epoll会被唤醒

android创建一个子线程 android handler两个子线程通信_Handler_18


在下一次执行sendMessage时会执行nativeWake,当向pipe管道写端mWakeWritePipeFd写入唤醒信号1时,读端mWakeReadPipeFd会收到信号1,由epoll机制可知从MessageQueue取Message所在的线程会被唤醒

总结:
当MessageQueue为空时,执行MessageQueue.next取出下一个Message时会休眠,休眠采用epoll机制监听pipe管道读端mWakeReadPipeFd的数据,若无数据则休眠;当下一次执行sendMessage时会执行nativeWake,向pipe管道写端mWakeWritePipeFd写入唤醒信号,此时执行MessageQueue.next的线程被唤醒

7. 总结

a. Looper.prepare()方法
主线程创建Looper,并创建MessageQueue保存到Looper.mQueue
主线程创建多个Handler:Handler1、Handler2、HandlerN,每个Handler在创建的过程中都会将Looper.mQueue保存到自己的mQueue中
b. HandlerN.sendMessage()方法
将sendMessage的调用者HandlerN保存到msg.target中,并将msg保存到HandlerN.mQueue中,由于HandlerN.mQueue等于Looper.mQueue,故即将Message保存到Looper的MessageQueue中
c. Looper.loop()方法
死循环逐一取出保存在Looper的MessageQueue中msg,由于msg.target保存着msg的发送者HandlerN,调用msg.target. dispatchMessage,最终HandlerN.handleMessage
当MessageQueue为空时会使用epoll休眠,当下一个Message放入Message时会被唤醒