消息循环针对的是线程。
从根本上来说Android系统同windows系统一样,也属于消息驱动型系统 消息驱动型系统会有以下4大要素:
- 接收消息的"消息队列"——【MessageQueue】主要功能式投递消息
- 阻塞式地从消息队列中接收消息并进行处理的"线程"——【Thread+Looper】
- 可发送的"消息的格式"——【Message】
- “消息发送函数”——【Handler的post和sendMessage】
一个Looper类似一个消息泵。它本身是一个死循环,不断从MessageQueue中提取Message或者Runnable。而Handler可以看作是一个Looper的暴露接口,向外部暴露一些事件,并暴露sendMessage()和post()函数
消息机制主要包含:
- Message:消息分为硬件产生的消息(如按钮、触摸)和软件生成的消息
- MessageQueue:消息队列的主要功能是向消息池投递消息(MessageQueue.enqueueMessage)和取走消息池的消息(MessageQueue.next)
- Handler:消息辅助类,主要功能是向消息池发送各种消息事件(Handler.sendMessage)和处理相应消息事件(Handler.handleMessage)
- Looper:不断循环执行(Looper.loop),按分发机制将消息分发给目标处理者
Looper类用来为一个线程开启一个消息循环。默认情况下android中新诞生的线程是没有消息循环的。默认情况下Handler会与其被定义时所在线程的Looper绑定。new Handler()等价于new Handler(Looper.myLooper())。故在非主线程中直接new Handler()会报错,原因时非主线程中没有创建Looper对象,需要先调用Looper.prepare()启用Looper。
通过Looper.myLooper()得到当前线程的Looper对象,通过Looper.getMainLooper()得到当前进程的主线程的Looper对象。
Looper.loop()则是让Looper开始工作,从消息队列里取消息,处理消息。写在Looper.loop()之后的代码不会被执行,这个函数内部应该时一个循环,只有在调用mHandler.getLooper().quit()后,loop才会终止,其后的代码才能运行
loop()进入循环模式,不断重复下面的操作,直到没有消息时退出循环
- 读取MessageQueue的下一条Message
- 把Message分发给相应的Handler
- 再把分发后的Message回收到消息池,以便重复利用
只有在子线程需要Looper.prepare()和Looper.loop(),因为主线程在初始化的时候已经创建了一个Looper对象了。
从上图可知,Looper负责消息循环,Handler负责发送和处理消息,MessageQueue则负责管理消息(消息的增加和移除)。不管是sendMessage还是sendMessageDelay或是View.post方法,或是上面列出的没列出的发送消息的方法,最终都会包装成一条消息Message(这条消息由Handler发出),然后调用MessageQueue的enqueueMessage方法把消息放到消息队列MessageQueue中。而Loop则会不停地查看MessageQueue中是否有新消息msg,有新消息就会调用新消息msg.target.handleMeassage()去处理消息,否则会一直阻塞。msg.target实际上是Handler对象。因此,Handler发送的消息,最终也是由Handler来处理。
最后用一张图,来表示整个消息机制:
图解:
- Handler通过sendMessage()发送Message到MessageQueue队列
- Looper通过loop(),不断提取出达到触发条件的Message,并将Message交给target来处理
- 经过dispatchMessage()后,交回给Handler的handlerMessage()来进行相应地处理。
- 将Message加入Message时,往管道写入字符,可以唤醒loop线程;如果MessageQueue中没有Message,并处于idle状态,则会执行idelHandler接口中的方法,往往用于做一些清理性地工作。