【Android】Handler原理解析

本文详细剖析了Android中Handler的工作原理,从Message和Looper的源码出发,解释了Message的回收机制、Looper的循环处理消息过程,以及Handler的构造函数、dispatchMessage与handleMessage的区别。此外,还探讨了如何发送消息,包括Message和Runnable方式的区别。
摘要由CSDN通过智能技术生成

要分析Handler的原理,首先需要了解Message和Looper,所以我们先来分析一下Message和Looper的源码。

Message

首先根据注释来看一下Message的定义:

/**
 *
 * Defines a message containing a description and arbitrary data object that can be
 * sent to a {@link Handler}.  This object contains two extra int fields and an
 * extra object field that allow you to not do allocations in many cases.
 *
 * <p class="note">While the constructor of Message is public, the best way to get
 * one of these is to call {@link #obtain Message.obtain()} or one of the
 * {@link Handler#obtainMessage Handler.obtainMessage()} methods, which will pull
 * them from a pool of recycled objects.</p>
 */

定义一个包含描述和任意数据对象的对象,将这个对象发送给Handler处理。这个对象包含两个额外的int字段和一个额外的object字段,但在很多情况下,这些字段并要求你必须给他们赋值。同时提醒我们,虽然Message的构造函数是public的,但是最好是调用Message.obtain()方法,这个方法会从回收池里获取Message对象。obtain方法是怎么回收利用Message的呢,从以下方法中分析:

/**
 * Return a new Message instance from the global pool. Allows us to  
 * avoid allocating new objects in many cases.
 */
public static Message obtain() {
    synchronized (sPoolSync) {
        if (sPool != null) {
            Message m = sPool;
            sPool = m.next;
            m.next = null;
            m.flags = 0; // clear in-use flag
            sPoolSize--;
            return m;
        }
    }
    return new Message();
}

1、这里的sPoolSync是一个Object实例,sPool是一个Message对象,如果sPool不为null的话,会将sPool赋值给一个新的Message对象,并将m.next赋值给sPool,m.next也是一个Message,同时,最终返回m。由于取出了一个Message,所以sPoolSize–,如果有另外线程调用Message.obtain,则会直接创建一个新的Message返回;

/**
 * Same as {@link #obtain()}, but copies the values of an existing
 * message (including its target) into the new one.
 * @param orig Original message to copy.
 * @return A Message object from the global pool.
 */
public static Message obtain(Message orig) {
    Message m = obtain();
    m.what = orig.what;
    m.arg1 = orig.arg1;
    m.arg2 = orig.arg2;
    m.obj = orig.obj;
    m.replyTo = orig.replyTo;
    m.sendingUid = orig.sendingUid;
    if (orig.data != null) {
        m.data = new Bundle(orig.data);
    }
    m.target = orig.target;
    m.callback = orig.callback;

    return m;
}

2、根据注释可以看出,该方法与obtain()方法一样,不同之处在于,这个方法的参数是一个已存在的Message,它首先调用botain()方法,获取一个已存在的Message,然后将参数Message的值赋值给m对应的属性,最终返回m。其他几个obtain方法都是多了一些传参,对m的某些值做了修改,就不多做赘述了,Message内部还有一些其他方法,但是一般在使用Handler时不会使用,所以就不予以描述了。

Looper

Looper对与Handler来说,是一个很重要的概念,不了解Looper就不能真正弄懂Handler的机制,所以,先来了解一下Looper,先看一下官方对与Looper的定义。

/**
  * Class used to run a message loop for a thread.  Threads by default do
  * not have a message loop associated with them; to create one, call
  * {
  @link #prepare} in the thread that is to run the loop, and then
  * {
  @link #loop} to have it process messages until the loop is stopped.
  *
  * <p>Most interaction with a message loop is through the
  * {
  @link Handler} class.
  *
  * <p>This is a typical example of the implementation of a Looper thread,
  * using the separation of {
  @link #prepare} and {@link #loop} to create an
  * initial Handler to communicate with the Looper.
  *
  * <pre>
  *  class LooperThread extends Thread {
   
  *      public Handler mHandler;
  *
  *      public void run() {
  *          Looper.prepare();
  *
  *          mHandler = new Handler() {
  *              public void handleMessage(Message msg) {
  *                  // process incoming messages here
  *              }
  *          };
  *
  *          Looper.loop();
  *      }
  *  }</pre>
  */

官方对与Looper的定义为,针对一个线程运行的消息循环。线程默认是没有消息循环相关联的,要创建一个消息循环,就要调用Looper的prepare方法,然后调用Looper的loop方法来循环处理消息,直到循环停止。下边官方也说明大多数与消息循环的交互是通过Handler来实现的。最后官方给出了一个创造包含消息循环的线程的例子。下边看一下Looper具体的代码:

 /** Initialize the current thread as a looper.
  * This gives you a chance to create handlers that then reference
  * this looper, before actually starting the loop. Be sure to call
  * {@link #loop()} after calling this method, and end it by calling
  * {@link #quit()}.
  */
 public static void prepare() {
    prepare(true);
 }

 private static void prepare(boolean quitAllowed) {
     if (sThreadLocal.get() != null) {
         throw new RuntimeException("Only one Looper may be created per thread");
     }
     sThreadLocal.set(new Looper(quitAllowed));
 }

通过注释可以看到,prepare方法可以将当前线程初始化为looper。并且该方法要在Looper.loop()方法之前调用,最后要调用quit()方法退出循环。这两个方法
唯一的不同就是多了一个boolean类型的参数。无参的prepare方法调用了有参的prepare方法,并默认参数为true。从有参的prepare方法中可以看到,有个sThreadLocal对象,并调用了该对象的get方法,我们看下它的get方法最终会返回什么:

/**
 * Returns the value in the current thread's copy of this
 * thread-local variable.  If the variable has no value for the
 * current thread, it is first initialized to the value returned
 * by an invocation of the {@link #initialValue} method.
 *
 * @return the current thread's value of this thread-local
 */
public T get() {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null) {
        ThreadLocalMap.Entry e = map.getEntry(this);
        if (e != null) {
            @SuppressWarnings("unchecked")
            T result = (T)e.value;
            return result;
        }
    }
    return setInitialValue();
}

首先,该方法会获取当前线程,并获取当前线程的ThreadLocalMap,ThreadLocal是一个定制的HashMap,是为了维护线程本地值而诞生的,如果当前线程的ThreadlocalMap不为null,则根据key,获取Entry,将Entry.value返回。如果map为null,则调用setInitialValue方法,再看这个方法是用来干什么的:

/**
 * Variant of set() to establish initialValue. Used instead
 * of set() in case user has overridden the set() method.
 *
 * @return the initial value
 */
private T setInitialValue() {
    T value = initialValue();
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值