天天看点

Android中Handler,Looper和MessageQueue工作原理解析

Handler

消息的处理者。通过Handler对象我们可以封装Message对象,然后通过sendMessage(msg)把Message对象添加到 MessageQueue中;当MessageQueue循环到该Message时,就会调用该Message对象对应的handler对象的 handleMessage()方法对其进行处理。由于是在handleMessage()方法中处理消息,因此我们应该编写一个类继承自 Handler,然后在handleMessage()处理我们需要的操作。

Looper

MessageQueue的管理者,在一个线程中,如果存在Looper对象,则必定存在MessageQueue对象,并且只存在一个Looper对象 和一个MessageQueue对象。倘若我们的线程中存在Looper对象,则我们可以通过Looper.myLooper()获取,此外我们还可以通 过Looper.getMainLooper()获取当前应用系统中主线程的Looper对象。在这个地方有一点需要注意,假如Looper对象位于应用 程序主线程中,则Looper.myLooper()和Looper.getMainLooper()获取的是同一个对象。

MessageQueue

MessageQueue顾名思义,就是消息队列,使用队的方式来管理Message,程序创建Looper对象时会在它的构造器中创建Looper对象,Looper的构造器如下:

private looper()
{
     mQueue = new MessageQueue();
     mRun=true;
     mThread=Thread.currentThread;
}
           

可以看出来,我们无法通过构造器创建Looper对象,但是程序在初始化时会创建一个MessageQueue,这个MessageQueue就负责管理消息。

当我们创建出一个子线程的话,想往自己创建的MessageQueue中发送消息,也就是说想让handler正常工作,但是如果在非ui线程中是没有MessageQueue的,那么怎么样才能有呢,根据上面的代码,可以看到,当我们创建出Loopre对象时便会创建出一个MessageQueue,所以我们可以使用Looper.prepare()来创建Looper

public static final void prepare()
{
    if(sThreadLocal.get()!=null)
    {
     throw ........
    }
    sThreadLocal.set(new Looper);
}
           

那么ThreadLocal是什么呢

ThreadLocal是什么

  早在JDK 1.2的版本中就提供java.lang.ThreadLocal,ThreadLocal为解决多线程程序的并发问题提供了一种新的思路。使用这个工具类可以很简洁地编写出优美的多线程程序。

  当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。

  从线程的角度看,目标变量就象是线程的本地变量,这也是类名中“Local”所要表达的意思。

  所以,在Java中编写线程局部变量的代码相对来说要笨拙一些,因此造成线程局部变量没有在Java开发者中得到很好的普及。

ThreadLocal的接口方法

ThreadLocal类接口很简单,只有4个方法,我们先来了解一下:

void set(Object value)设置当前线程的线程局部变量的值。

public Object get()该方法返回当前线程所对应的线程局部变量。

public void remove()将当前线程局部变量的值删除,目的是为了减少内存的占用,该方法是JDK 5.0新增的方法。需要指出的是,当线程结束后,对应该线程的局部变量将自动被垃圾回收,所以显式调用该方法清除线程的局部变量并不是必须的操作,但它可以加快内存回收的速度。

protected Object initialValue()返回该线程局部变量的初始值,该方法是一个protected的方法,显然是为了让子类覆盖而设计的。这个方法是一个延迟调用方法,在线程第1次调用get()或set(Object)时才执行,并且仅执行1次。ThreadLocal中的缺省实现直接返回一个null。
           

那么我们便可以理解了 sThreadLocal.set(new Looper())用一个ThreadLocal记录住Looper是哪个线程的Looper,以便用来调用

说的有点远。。。。。

当我们创建出Looper对象时,我们调用Looper.loop()方法启动它,

loop()方法是一个死循环用来不断的从MessageQueue中取出消息,并将取出的消息分给该消息对应的Handler进行处理,下面是Looper.loop()的部分源码

for(;;)
{
        Message msg = queue.next();
        if(msg==null)
        return;
//。。。。。。。。。消息处理等等
}
           

归纳起来:

handler:能把消息发送给Looper管理的MessageQueue,并负责处理Looper分发的消息

Looper:一个线程只有一个Looper 负责管理MessageQueue,不断从MessageQueue中取出消息,分给对应的Handler

MessageQueue:用队的方式管理Message