【面试】一个线程能否创建多个Handler,Handler跟Looper之间的对应关系 ?

14 篇文章 1 订阅

1 一个线程能否创建多个Handler,Handler跟Looper之间的对应关系 ?

一个线程能够创建多个Handler,Handler跟Looper没有对应关系,线程才跟Looper有对应关系,一个线程对应着一个Looper,如下所示:

private static void prepare(boolean quitAllowed) {
    if (sThreadLocal.get() != null) {
        throw new RuntimeException("Only one Looper may be created per thread");
    }
    //将Looper存到当前线程的ThreadLocal中
    sThreadLocal.set(new Looper(quitAllowed));
}

创建Handler时,需要先调用Looper的prepare方法,在该方法中,会首先判断sThreadLocal.get()是否为空,如果不为空就抛出异常,内容是:一个线程只能创建一个Looper。如果sThreadLocal.get()为空,则会创建一个Looper对象并存入sThreadLocal中。

创建多个Handler方式如下:

      Looper.prepare();
      Handler handler = new Handler(){
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
            }
      };
      Handler handler1 = new Handler(){
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
            }
      };
      Looper.loop();

上述代码并不是最完美的代码,没有考虑内存泄漏,代码规范等,只是简单的为了说明该如何使用而已。在主线程中,我们只需要创建Handler就行,不需要调用Looper.prepare()和Looper.loop(),因为在android应用启动时,主线程已经调用了Looper.prepareMainLooper方法帮我们创建了Looper对象,因此不需要我们再自己重新创建。有人会问,那么我们如何知道哪条消息是哪个handler发送的呢?Looper取出消息又如何发送到指定的Handler呢?

2 Looper取出消息又如何发送到指定的Handler呢?

上述我们说到,一个线程对应一个Looper,可以对应多个Handler,这里的Looper和handler都属于同一个线程。而每个线程都有一个属于自己的ThreadLocalMap,Looper对象就存储在线程的ThreadLocalMap中(如上述代码所示)。从handler发送消息,最终会调用Handler类中的enqueueMessage方法,该方法源码如下所示:

    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

我们看该方法的第一句

msg.target = this;

我们可以看下Message类中的target是什么

    /*package*/ Handler target;

可以看到该target是一个Handler类型,所以msg的target指向了当前Handler对象,然后msg被加入到消息队列,通过调用下面代码

queue.enqueueMessage(msg, uptimeMillis);

消息存入消息队列后,就会唤醒Looper,然后Looper就会从loop方法中获取消息,如下所示:

public static void loop() {
      final Looper me = myLooper();
      ......
}
public static @Nullable Looper myLooper() {
      return sThreadLocal.get();
}

me就是线程中prepare方法里创建的Looper对象,该Looper对象里有个消息队列,如下方法获取消息队列

final MessageQueue queue = me.mQueue;

该消息队列中存储着通过handler发送过来的Message,而MessageQueue通过下列方法从消息队列中取出消息

public static void loop() {
    ......
    for (;;) {
        Message msg = queue.next(); // might block
        ......
    }

该消息中封装着发送消息的handler对象,取出消息后,就会通过dispatchMessage方法将消息分发出去,如下所示:

    msg.target.dispatchMessage(msg);

这句的意思就是将msg发送到指定的Handler中。

3 总结

  • 一个线程可以创建多个Handler,但只能创建一个Looper,一个MessageQueue。Handler跟Looper之间没有对应关系
  • Handler通过sendMessage发送消息时,就会将handler对象存储到message中,然后Looper在loop中通过MessageQueue的next方法取出消息后,会通过之前消息封装的handler将消息发送到指定的handler,即通过调用msg.target.dispatchMessage方法。
  • 6
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值