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

  在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 sThreadLocal = new ThreadLocal();

  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时采用的构造函数不一样,采用不同的方法来处理消息。

你可能感兴趣的:(Android)