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

private Handler handler = new Handler(){@Overridepublic 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时采用的构造函数不一样,采用不同的方法来处理消息。

更多相关文章

  1. SpringBoot 2.0 中 HikariCP 数据库连接池原理解析
  2. android 深入解析AsyncTask
  3. Android(安卓)多线程:HandlerThread理解和使用总结
  4. android自定义dialog弹出框、透明背景
  5. Android(安卓)多线程:手把手教你使用AsyncTask
  6. android 跨进程访问service方法
  7. 发现3 .js与Android和英特尔XDK
  8. Handler发送消息后消息队列的处理
  9. 【Android(安卓)Training UI】创建自定义Views(Lesson 2 - 自定

随机推荐

  1. Android(安卓)使用WiFi打印
  2. Android之个性化ListView实现
  3. Android系统架构基本模式解析
  4. 如何实现android EditText允许输入字母和
  5. Android(安卓)ROM分析(1):刷机原理及方法
  6. Android(安卓)日历开发教程[六]
  7. Android(安卓)Studio 出现 Gradle's depe
  8. Android多点触控
  9. Fuchsia OS 要取代 Android?小论Google Fu
  10. Android(安卓)源码分析-Dalvik 虚拟机创