从开发角度来说,Handler是Android消息机制的上层接口,这使得开发过程中只需要和Handler交互即可。
1.1、Android的消息机制概述
简单来讲,Handler的运行需要底层的MessageQueue和Looper的支撑。MessageQueue是消息队列,它的内部存储了一组消息,以队列的的形式对外提供插入和删除的工作,它的内部是采用单链表的数据结构来存储消息列表。Looper可以理解为消息循环。Looper会以无限循环的形式在MessageQueue中查找是否有新消息,如果有就处理消息,否则一直等待着。Looper中还有一个特殊的概念,那就是ThreadLocal,ThreadLocal并不是线程,它的作用是可以在每个线程中存储数据。
Handler创建的时候会采用当前线程的Looper来构造消息循环系统,ThreadLocal可以再不同的线程中互不干扰地存储并提供数据,通过ThreadLocal可以轻松的获取每个线程的Looper。
注意,线程默认是没有Looper的,如果需要使用Hnadler就必须为线程创建Looper。我们经常提到的主线程也叫UI线程,他就是ActivityThread,ActivityThread被创建时就会初始化Looper,这也是主线程中默认可以使用Handler的原因。
Android无法在子线程中更新UI,因为Android的UI控件不是线程安全的。
注意,Looper是运行在创建Handler所在的线程中的,这样一来Handler中的业务逻辑就会被切换到创建Handler所在的线程中去执行了。
1.2、Android的消息机制分析
1.2.1、ThreadLocal的工作原理
ThreadLocal是一个线程内部的数据存储类,通过它可以在指定的线程中存储数据。只有在指定的线程中可以获取到数据。
不同的线程创建了不同的Values,Values下有不同的数组table,所以不同的线程存储的数据不同。
1.2.2、MessageQueue的工作原理
MessageQueue包含两个操作:插入和读取。读取操作本身伴随着删除操作,插入和读取对应的方法分别是enqueueMessage(插入一条消息到消息队列)和next(取出一条消息并将其从消息队列中移除)。
1.2.3、Looper的工作原理
private Looper(boolean quitAllowed){
mQueue = newMessageQueue(quitAllowed) ;
mThread = Thread.currentThread() ;
}
从构造方法可以看出,Looper会创建一个MessageQueue,然后将当前线程对象保存。
Handler的工作需要Looper,没有Looper的线程就会报错。创建Looper:
Looper.prepare()即可为当前线程创建一个Looper,接着通过Looper.loop()来开启消息循环。
Looper提供了quit(直接退出)和quitSafely(消息队列里的消息执行完毕才退出)来退出一个Looper。
子线程中如手动创建了Looper,所有事情处理完后应该调用quit,否则子线程一直等待状态。
当Looper方法是一个死循环,唯一跳出循环的方式是MessageQueue的next方法反回了nul。当Looper的quit方法调用时,Looper就会调用MessageQueue的quit或者quitSafely方法来通知消息队列退出,当消息队列标记为退出状态是,它的next方法就会返回null。
所以说Looper必须退出,否则loop就会一直循环下去。当loop方法去调用MessageQueue的next方法来获取新消息,而next是一个阻塞操作,当没有消息时,next方法会一直阻塞,导致loop方法一直阻塞在那里。有消息looper处理:msg.target.dispatchMessage(msg) ;msg.target是发送这条消息的Handler对象。
1.2.4、Handler的工作原理
Handler的工作包括消息的发送和接收过程。发送可用post系列方法和send系列方法。(post最终通过send)。
Handler发送消息的过程仅仅是向消息队列中插入了一条消息,MessageQueue的next方法就会返回这条消息给Looper,Looper收到消息后就开始处理消息,最终消息由Looper交给Handler处理,即handler的dispatchMesage方法被调用。
Handler处理消息的三个方式对应dispatchMesage方法的三个处理情况 :
1)handler.post(Runnable r)
2) handler = new Handler(callback)
3) 派生子类,重写handleMessage方法。
Handler还有一个特殊的构造方法,那就是通过特定的Looper来构造Handler
public Handler (Looper looper){
this(looper,null,false) ;
}
可以实现一些特殊的功能。