Handler的创建、Message的处理与Looper的作用——源码分析

分析源码,总结小过程(源码只打印出重要部分):

一般Hanlder的创建:
//Handler的部分构造方法
public Handler() {
  this(null, false);
}

public Handler(Callback callback, boolean async) {
  mLooper = Looper.myLooper();
  if (mLooper == null) {
   throw new RuntimeException(
    "Can't create handler inside thread that has not called Looper.prepare()");
  }
  mQueue = mLooper.mQueue;
  mCallback = callback;
  mAsynchronous = async;
}
Handler中有几个重要的全局变量:mLooper、mQueue、mCallback,分别为此Handler所在的线程的Looper对象、消息队列、还有Handler的回调接口(此接口有handleMessage()方法,实现此接口可以替代,必须匿名内部类重写Handler的handleMessage()方法的情况)。

在以上源码中可看出创建Handler的时候会调用Looper的静态方法myLooper():
public static @Nullable Looper myLooper() {
  return sThreadLocal.get();
}
此方法会去访问Looper对象中的属性ThreadLocal对象的get()方法:
public T get() {
  // Optimized for the fast path.
  Thread currentThread = Thread.currentThread();//获取当前线程
  Values values = values(currentThread);//获取线程对应的ThreadLocal.Values对象

  return (T) values.getAfterMiss(this);//获取Values中的Looper对象
}
即它会去访问当前线程中的属性ThreadLocal.Values对象,对象中维护了一个一维Object数组,数组顺序交替保存了ThreadLocal和Looper对象,所以可以从整体上看待ThreadLocal,把它当作一个Map对象(Java的ThreadLocal的确维护着一个Map对象),里面存着以ThreadLocal为key,以Looper对象为value的键-值对。最后通过Values的getAfterMiss()方法返回当前线程对应的Looper对象。

总结, Handler在哪个线程中创建,它都会与当前线程的Looper绑定在一起,操作的消息队列也是当前线程与其Looper所维护的消息队列

Looper的创建:
1)首先我们来看一下官方API对Looper的介绍:
Looper用来在线程中执行一个消息队列(原文是“message loop”在此翻译为消息队列会比较好译)。线程默认情况都不会有与之关联的消息队列。如果在线程调用prepare(),那么会创建一个Looper与该线程关联,线程就拥有了自己的消息队列。并且必须调用loop()方法到执行消息队列直到队列被停止。
一般用户与消息队列的交互都是通过Handler类,以下是一个典型的例子:
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();
 }
}
源码前的分析:当线程有了自己的Looper(也拥有了消息队列),在它的代码就可以创建Handler来与用户交互,即Handler在哪个线程创建,它就属于哪个线程,它发送的消息Message也会加入它所属的线程的消息队列中。如果线程没有Looper就创建Handler类对象会产生"Can't create handler inside thread that has not called Looper.prepare()"异常。自己在线程中维护一个Looper要注意可能必须调用quit()方法来关闭Looper。

2)再来看源码。Looper的构造方法和一些重要的全局变量:
// sThreadLocal.get() will return null unless you've called prepare().
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private static Looper sMainLooper; // guarded by Looper.class

final MessageQueue mQueue;
final Thread mThread;

private Looper(boolean quitAllowed) {
  mQueue = new MessageQueue(quitAllowed);
  mThread = Thread.currentThread();
}
新建消息队列并保存当前线程到全局变量mThread中。因为此方法是私有,所以只能在内部实例化,这就用到了我们常见的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));
}
由源码可知,创建Looper时会先尝试从ThreadLocal对象中获取,如果ThreadLocal中还没保存Looper,就会新建一个Looper对象并保存到ThreadLocal(其中的Thread.Values的数组中)中, 这就保证了一个线程中只有一个Looper当线程调用了prepare()方法,Looper会将当前线程的对象保存到mThread变量中,即绑定了当前创建它的线程。线程有了自己的Looper和MessageQueue后,必须调用Looper.loop()方法(源码请看“Handler的消息处理”),让消息队列开始运转

Looper还有个重要的方法(对系统而言):
public static void prepareMainLooper() {
  prepare(false);
  synchronized (Looper.class) {
  if (sMainLooper != null) {
  throw new IllegalStateException("The main Looper has already been prepared.");
  }
  sMainLooper = myLooper();
  }
}
它将当前线程的Looper设置为整个应用的主要Looper(他属于UI线程)。应用的主要Looper是由安卓环境创建的,所以开发者不需要自己去调用他。

Handler的消息处理
public final boolean sendMessage(Message msg)
{
  return sendMessageDelayed(msg, 0);
}

public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
  if (delayMillis < 0) {
  delayMillis = 0;
  }
  return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}

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);
}

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
  msg.target = this;//将消息执行完成要回调的handleMessage()方法所属的对象设置为当前对象
  if (mAsynchronous) {
  msg.setAsynchronous(true);
  }
  return queue.enqueueMessage(msg, uptimeMillis);
}
平时我们调用的sendMessage(Message msg)方法经过一些参数的判断和处理后,最终到了enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) 方法中来实现功能;在这里,将我们想发送的Message对象的target设为当前Handler对象,这就是为什么MessageQueue中有很多Message,但执行时可以回调到正确的Handler对象的原因。最后用了MessageQueue的enqueueMessage(msg, uptimeMillis)方法将消息推入队列中。

Looper.prepare()调用后,都必须调用Looper.loop()方法以运转消息队列,这样Handler发的消息才可以被处理:
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(); // 可能会堵塞
  if (msg == null) {
  // 没有消息,意味着消息队列正在退出
  return;
  }

  msg.target.dispatchMessage(msg);//派遣任务,让Handler处理消息内容

  msg.recycleUnchecked();//回收消息对象,标为“非在用”状态
  }
}
从上面的源码可以看出,消息队列一直无止境地循环获取消息,而消息的处理则是Message对象中的target,处理任务又回到了Handler中:
public void dispatchMessage(Message msg) {
  if (msg.callback != null) {//如果有线程任务,则执行线程
  handleCallback(msg);
  } else {
  if (mCallback != null) {
  if (mCallback.handleMessage(msg)) {
  return;
  }
  }
  handleMessage(msg);
  }
}

private static void handleCallback(Message message) {
  message.callback.run();
}
Handler会优先判断是否有实现了Handler.CallBack接口的类对象mCallback,如果没有直接回调Handler的handleMessage()方法;有则回调该对象的handleMessage()方法,并且判断消息是否继续传递到Handler的handleMessage()方法。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值