在写一些回调的时候,有可能会需要子线程切回到主线程进行控件刷新,这个时候就需要用到handler了。以前每次用都在网上搜了用法直接照着写,也不知道内部原理,在看了任玉刚大神的《Android开发艺术探索》后,对Android的消息机制有了一个基本了解。
概要
Android的消息机制主要是指Handler的运行机制,以及所附带的MessageQueque和Looper的工作过程。主要组成及核心方法
Android的消息机制主要涉及到4个方面的配合运行:- Handler 发送和接收消息,分别为post(Runnable r)或sendMessage(Message msg)及dispatchMessage(Message msg)方法
- ThreadLocal 在指定的线程中存储数据,一般当某些数据以线程为作用域且不同线程具有不同的副本时,可考虑采用。存取分别为set(T value)、get()方法。只能存储一组值,多次调用set会覆盖原来的值。在这里,ThredLocal是保存当前线程Looper对象
- MessageQueue 消息队列,单链表,enqueueMessage(Message msg,long when)方法将Message插入链表中;next()方法会不停循环直到有Message,移除并返回Message
- Looper 读取消息并分发,运行在创建Handler所在的线程中,loop()方法中循环调用MessageQueue.next()方法获得Message,让Handler处理。若不再使用Looper可调用quit和quitSafely,quit会直接退出Looper,quitSafely只设定个退出标记,将消息队列中消息处理完后再退出。退出后,Handler发送的消息会失败
主要流程
如果是在UI线程,即ActivityThread,在创建时就会初始化Looper,所以在UI线程创建Handle就可直接获得Looper;如果是子线程,就要先调用Looper.prepare()(prepare()作用是将当前线程的Looper存放在ThreadLocal中);
然后创建Handler(Handler可以指定线程,可通过Looper.getMainLooper()指定主线程。创建Handler的线程或指定的线程即为Looper运行的线程。在创建Handler时也会获得Looper中MessageQueue对象);
最后调用Looper.loop()(MessageQueue是Looper中的一个变量,通过调用loop()方法不停的查看MessageQueue中是否有message,即loop()方法中调用MessageQueue的next()方法。next()作用是,当queue有message就返回并删除,如果没有就一直阻塞在这里,返回的message则让Handler处理)。示例如下:new Thread( new Runnable(){ Looper.prepare(); Handler handler = new Handler(); Looper.loop(); } ).start();
如果是在UI线程中,则只创建Handler即可,因为在UI线程创建时已经通过Looper.prepareMainLooper()来创建主线程的Looper
当Handler send一个message或post一个runnable(post先会obtain一个message,runnable作为message的callback返回message)时,会调用MessageQueue的enqueueMessage方法将其保存。
- Looper的loop()方法检测到有Message,则调用Message的target即Handler的dispatchMessage(Message msg)方法进行处理。
- 在dispatchMessage(Message msg)方法中如果Runnable,则调用run()方法,如果不是则调用handleMessage()方法。