Android Handler消息传递机制详解

1.为什么要用Handler

  出于性能优化的考虑,Android UI操作并不是线程安全,如果有多个线程并发操作UI组件,可能导致线程安全问题。可以设想下,如果在一个Activity中有多个线程去更新UI,并且都没有加锁机制,可能会导致什么问题? 界面混乱,如果加锁的话可以避免该问题但又会导致性能下降。因此,Android规定只允许UI线程修改Activity的UI组件。当程序第一次启动时,Android会同时启动一条主线程(Main Thread),主线程主要负责处理与UI相关的事件,比如用户按钮事件,并把相关的事件分发到对应的组件进行处理,因此主线程又称为UI线程。那么怎么在新启动的线程中更新UI组件呢,这就需要借助handler的消息传递机制来实现了。

2.Handler简介

  Handler类的主要作用主要有两个:

    1>在新启动的线程中发送消息

    2>在主线程中获取和处理消息

  Handler类包含如下方法用于发送、处理消息。(这里只列出常用的方法,如果想获取更多方法,建议查看api文档:)

    ♦ void handlerMessage(Message msg):处理消息的方法,该方法通常用于被重写。

    ♦ final boolean hasMessage(int what):检查消息队列中是否包含what属性为指定值的消息。

    ♦ sendEmptyMessage(int what):发送空消息

    ♦ final boolean sendMessage(Message msg):立即发送消息,注意这块返回值,如果message成功的被放到message queue里面则返回true,反之,返回false;(个人建议:对于这类问题不必主观去记它,当实际使用时,直接查看源码即可,源码中有详细的注释)

3.Handler、Message、Looper、MessageQueue之间的关系、工作原理

  为了更好的理解Handler,先来看看和Handler相关的一些组件:

    Message:Handler发送、接收和处理的消息对象

    Looper:每个线程只能拥有一个Looper.它的looper()方法负责循环读取MessageQueue中的消息并将读取到的消息交给发送该消息的handler进行处理。

    MessageQueue:消息队列,它采用先进先出的方式来管理Message。程序在创建Looper对象时,会在它的构造器中创建MessageQueue。源码如下:

    

1   private Looper(boolean quitAllowed) { 2 mQueue = new MessageQueue(quitAllowed); 3 mThread = Thread.currentThread(); 4 }

    从源码第2行中可以看出,在创建Looper对象时会创建一个与之关联的MessageQueue对象。构造器是private修饰的,所以程序员是无法创建Looper对象的。

    Handler:前面说Handler作用有两个---发送消息和处理消息,Handler发送的消息必须被送到指定的MessageQueue,也就是说,要想Handler正常工作必须在当前线程中有一个MessageQueue,否则消息没法保存。而MessageQueue是由Looper负责管理的,因此要想Handler正常工作,必须在当前线程中有一个Looper对象,这里分为两种情况:

      1>主线程(UI线程),系统已经初始化了一个Looper对象,因此程序直接创建Handler即可

      2>程序员自己创建的子线程,这时,程序员必须创建一个Looper对象,并启动它。

    创建Looper使用:Looper.prepare(),查看源码:

1   public static void prepare() { 2 prepare(true); 3 } 4 5   private static void prepare(boolean quitAllowed) { 6 if (sThreadLocal.get() != null) { 7 throw new RuntimeException("Only one Looper may be created per thread"); 8 } 9 sThreadLocal.set(new Looper(quitAllowed)); 10 } 11 12   private Looper(boolean quitAllowed) { 13 mQueue = new MessageQueue(quitAllowed); 14 mThread = Thread.currentThread(); 15 }

    通过方法调用,第9行创建Looper对象,创建Looper对象时同时会创建MessageQueue对象(第13行)。此外,可以看出prepare()允许一个线程最多有一个Looper被创建。

    然后调用Looper的looper()方法来启动它,looper()使用一个死循环不断取出MessageQueue中的消息,并将消息发送给对应的Handler进行处理。下面是Looper类中looper()方法的部分源码:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/b6d25354526072f57dde4f693ff7632b.html