# Android中的消息机制

TIP

本节内容:

一.什么是Handler;

二.Handler、Looper和MessageQueue的基本原理;

三.通过Handler实现线程间的通信;

四.初步分析Handler的工作原理;

# 一.什么是Handler?

Handler实际上就是一个处理器,在Android官方文档中并未对其有过精确的定义,

但我们可以将Handler、Looper和MessageQueue看作成一个整体,

其构成的这个整体就是Android中最重要的消息传递和消息处理机制。

在程序中,Handler是个类,所在的包结构:android.os.Handler;这里的包名os指的是:operation syster,即操作系统。

# 二.Handler、Looper和MessageQueue的基本原理;

Handler不断的将消息对象放入到消息队列里面,

Looper不断的向消息队列里面取消息对象(如果消息队列里面没有消息对象的话,Looper就处于等待的状态),取出后再交给Handler来处理。

如下图所示:

1

# 三.通过Handler实现线程间的通信;

# 1.在主线程当中定义一个类继承Handler并实现handlerMessage()方法;

# 2.在Worker Thread中通过Handler发送消息。

即在线程的run()方法中创建消息对象并使用Handler发送该对象。代码如下:

Message msg = handler.obtainMessage();
msg.属性 = 要赋得值;例如:msg.obj=””;
1
2

handler.sendMessage(msg); 这句代码相当于做了四件事情:

WARNING

(1)这句代码将消息对象首先发送(放置)到消息队列当中;

(2)Looper将会从消息队列当中将消息对象取出;

(3)Looper将会找到与消息对象对应的Handler对象;

(4)Looper将会调用Handler对象的handlerMessage(Message msg)方法,用于处理消息对象。

注意:sendMessage()方法无论是在主线程当中还是在工作线程当中发送都是可以的。

这样就解决了工作线程与主线程之间的通信问题。

# 四.初步分析Handler的工作原理;

结合上面的代码案例及Android源码,

# 1.handler.obtainMessage()这句代码的工作是这样的:

(1)首先在obtainMessage()方法中执行obtain(this)这句代码,

即:调用了obtain(Handler handler)方法,所传参数this指的是当前的Handler对象。

(2)在obtain(Handler handler)方法中首先调用了无参的obtain()方法,该方法创建了一个Message对象并返出,

因此在obtain(Handler handler)方法中得到了一个Message对象,然后将传进来的参数(也就是当前的Handler对象)赋值给这个Message对象的target属性。

这样就在HandlerMessage之间建立了对应关系,这种对应关系是一对多的关系,

即:一个Handler可以生成多个Message对象。

在这里总结为一句话:使用Handler生成Message,所生成的Message对象的target属性就是该Handler对象。

# 2.要想在Worker Thread中使用Looper的方法,

WARNING

首先调用Looper.prepare()方法;

然后生成一个Handler对象,调用其构造方法:

mHandler = new Handler(){
    public void handlerMessage(Message msg){
    //这里处理传入的消息}; 
1
2
3
4
5

然后再调用Looper.loop()方法。

(1)先从Looper.prepare()方法说起,这个方法就是

建了一个Looper对象作为值、以当前线程为键然后存入线程本地变量sThreadLocal(即:ThreadLocal) ,

这样就将LooperThread建立了对应关系(一个线程只能有一个Looper对象)。

而在Looper对象的构造方法中又创建了一个MessageQueue对象赋值给成员变量mQueue,并取得当前线程的对象赋值给成员变量mThread, (这样就将MessageQueueThread建立了对应关系);

(2)然后在Handler的构造方法中调用Looper.myLooper()

方法根据线程本地变量sThreadLocal取出了Looper对象赋值给Handler的成员变量mLooper,该对象又取出了其属性mQueue(也就是MessageQueue对象)赋值给了Handler的成员变量mQueue

截止到现在,LooperMessageQueueHandler三者之间已建立起了一一对应的关系,

即一个Handler对应一个Looper对象,一个Looper对应一个MessageQueue对象。

(3)调用Looper.loop()方法从消息队列中循环的向外取出数据。

该方法中,首先获取到消息队列的对象mQueue。然后执行for(;;)循环。

该方法中的for(;;)while(true) 循环一样,都是死循环,直到遇到break才停止。

在这个循环中,首先取Message对象(通过MessageQueue对象的next()方法)并赋值给局部变量msg,如果没有就处于阻塞状态,

如果有且Message对象不为null的时候,调用msg.target.dispatchMessage(msg)方法并将当前的消息对象作为参数传递,因为msg.target得到的是Handler对象,那么这里其实是调用了Handler的dispatchMessage(msg)方法,在该方法中又调用了handlerMessage(Message msg)方法来处理消息对象。

# 补充: 关于ThreadLocal;

ThreadLocal是java当中跟线程有关的一个类,严格意义上来讲,应将它叫做线程本地变量,

那么什么叫做线程本地变量?其实就是保存与当前线程相对应的值的变量。

ThreadLocal可以想象成是一个特殊的HashMap,只不过HashMap的键值都是obj对象,而ThreadLocal的键则是线程对象。

当执行ThreadLocal对象的set(Object obj)方法时,

将会存入一个以当前线程对象为键、以所传入参数为值的键值对。

执行ThreadLocal对象的get()方法(该方法无参),

将会根据当前线程对象为键,取出与之对应的值。

也就是说,当执行set(Object obj)方法时,实际上就是向ThreadLocal当中添加一个键值对。

线程4 值4
线程3 值3
线程2 值2
线程1 值1