欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Android多线程(二)消息处理机制---Handler、Message、Looper源码原理解析

程序员文章站 2022-07-14 19:48:16
...

  在Android中UI操作不是线程安全的,只有UI线程才能修改UI,所以我们经常开启子线程去处理一些耗时的操作,然后通过Handler发送消息,在UI线程中接送消息并处理UI组件,一个典型的Handler写法如下:

private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
    super.handleMessage(msg);
    switch (msg.what) {      
        ......
    }
 }

Runnable runnable = new Runnable()
{
    public void run()
    {
        ......
        handler.postDelayed(update_thread, 1000);
        ......
    }
};

或者在子线程中创建Handler:

class ChildThread extends Thread {  

    public void run() {  
        Looper.prepare();  
        mHandler = new Handler() {  
            public void handleMessage(Message msg) {  
            ......
            }  
        };  
        Looper.loop();  
    }  
}  

  为什么在子线程使用Handler需要调用Looper.prepare()和Looper.loop(),而主线程中不需要呢?下面,我们就从源码中解析一下Handler的消息处理机制。

Looper工作原理

我们来看一下Looer的构造函数:

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

  在构造函数中创建了一个MessageQueue,正如它的名字,这是一个消息队列,发送的Message都会从消息队列中插入和取出,此外还保存了当前所处的线程mCurrent。注意,Looper的构造函数是private修饰的,也就是说不能通过new来创建一个Looper,只能通过Looper类里面的其他方法来获取,接着看一下prepare()这个方法:

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很特殊,是存放在sThreadLocal里面的,sThreadLocal是Looper里面一个很重要的成员变量:

static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

  Threadlocal保证了我们创建的对象只能被当前的线程访问,即每个线程的Looper都是独有的,而且每个线程只能拥有一个Looer对象,否者就会抛出异常”Only one Looper may be created per thread”。看到这里,也就是解释了为什么在线程中使用Handler时需要调用Looper.prepare(),那为什么在UI线程中不需要调用Looper.prepare()呢,其实在Looper中还有一个方法:

/**
 * Initialize the current thread as a looper, marking it as an
 * application's main looper. The main looper for your application
 * is created by the Android environment, so you should never need
 * to call this function yourself.  See also: {@link #prepare()}
 */
public static void prepareMainLooper() {
    prepare(false);
    synchronized (Looper.class) {
        if (sMainLooper != null) {
            throw new IllegalStateException("The main Looper has already been prepared.");
        }
        sMainLooper = myLooper();
    }
}

  从注释中可知,当我们创建一个应用的时候,系统就已经为创建了一个main looper了,因此当我们使用Handler时就默认使用了这个main looper。Looper.prepare()完成之后接下来就是Looper.loop(),只有调用loop()之后,消息循环系统才真正地运行起来:

public static void loop() {
    final Looper me = myLooper();
    if (me == null) {
        throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
    }
    final MessageQueue queue = me.mQueue;
    ......
    for (;;) {
        Message msg = queue.next(); // might block
        if (msg == null) {
            // No message indicates that the message queue is quitting.
            return;
        }
       try {
            msg.target.dispatchMessage(msg);
        } finally {
        ......
        }
        ......
        msg.recycleUnchecked();
    }
}
public static @Nullable Looper myLooper() {
    return sThreadLocal.get();
}

  从以上代码看到,loop()方法中通过myLooper()获取了在prepare()中创建的Looper对象,接下来就是一个死循环,只有MessageQueue的next为null即消息为空时才能跳出循环。如果消息不为空,接着就调用msg.target.dispatchMessage(msg)去处理消息,msg.target就是我们创建的Handler对象,消息处理流程在这切换到了Handler中,这样就把Looper、Handler、Message、MessageQueue联系起来了。

Handler工作原理

  Handler主要的工作就是发送和接收消息,发送消息是通过一系列的postXXX和sendXXX方法实现的,以上一系列方法最终调用的是sendMessageAtTime()这个方法:

public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
    MessageQueue queue = mQueue;
    if (queue == null) {
        RuntimeException e = new RuntimeException(
                this + " sendMessageAtTime() called with no mQueue");
        Log.w("Looper", e.getMessage(), e);
        return false;
    }
    return enqueueMessage(queue, msg, uptimeMillis);
}

sendMessageAtTime()负责将Message压如MessageQueue中,然后MessageQueue的next()取出Message交给Handler的dispatchMessage()去处理:

 /**
  * Handle system messages here.
  */
 public void dispatchMessage(Message msg) {
     if (msg.callback != null) {
         handleCallback(msg);
     } else {
         if (mCallback != null) {
             if (mCallback.handleMessage(msg)) {
                 return;
             }
         }
         handleMessage(msg);
     }
 }

如果Message的callback不为空的情况下就通过handleCallback(msg)来处理消息,这里的callback其实是一个Runnable对象,也就是通过post(Runnable r)传入的;如果msg.callback为空,则去检查mCallback是否为空,这个mCallback是Handler内部的一个接口:

/**
 * Callback interface you can use when instantiating a Handler to avoid
 * having to implement your own subclass of Handler.
 *
 * @param msg A {@link android.os.Message Message} object
 * @return True if no further handling is desired
 */
public interface Callback {
    public boolean handleMessage(Message msg);
}

  如果我们创建Handler的时候使用的是Handler(Callback callback)的话,就需要重写Callback接口的handleMessage(Message msg)方法,这样消息的处理就由Callback处理,如果没有传入自己的Callback,最后就会调用Handler自己的handleMessage(Message msg)来处理消息,这也是我们最常用的方式。

总结

这样,Handler处理消息的流程就分析完了,我们来总结一下:
1、首先我们通过Looper.prepare()创建了一个Looper对象,如果是UI线程的话,系统则会自动为我们通过prepareMainLooper()创建Looper对象,然后在Looper中创建了一个消息队列MessageQueue,每个线程都只对应这个唯一的Looper,每隔Looper又对应着唯一一个MessageQueue;
2、Looper.loop()是一个死循环,不断地从MessageQueue中取出Message交给Handler的 dispatchMessage处理;
3、Handler通过创建Handler时采用的构造函数不一样,采用不同的方法来处理消息。