在消息机制里面,有一个非常重要的东西,那就是Looper,Looper的作用主要是从消息队列里面取出消息交给Handler处理,不过不仅限于此,在这里面还有很多东西值得我们去源码看一看:

1.从Looper.prepare()开始

要在一个线程里面处理消息,代码如下:

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

代码其实只有关键性的一句,就是sThreadLocal.set(new Looper(quitAllowed)),首先来看看sThreadLocal

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

ThreadLocal:代表了一个线程局部的变量,每条线程都只能看到自己的值,并不会意识到其它的线程中也存在该变量。

在这里ThreadLocal的作用是保证了每个线程都有各自的Looper

上面的判断也说明了一个问题:一个线程只能有一个Looper

接下来看看创建Looper实例的方法new Looper(quitAllowed)

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

在构造方法里,初始化了MessageQueue和代表当前线程的属性mThread,关于MessageQueue可以看看文章开头的链接,里面有详细的代码解析,这里就不赘述了。

调用Looper.prepare()其实就是利用ThreadLocal为当前的线程创建了一个独立的Looper,这其中包含了一个消息队列

2.创建Handler->new Handler()

在为当前线程创建了Looper之后,就可以创建Handler来处理消息了,这里可以解决我们一个疑问:

Handler是怎么跟Looper关联上的?

//全局变量
final Looper mLooper;
final MessageQueue mQueue;public Handler(Callback callback, boolean async) {if (FIND_POTENTIAL_LEAKS) {final Class<? extends Handler> klass = getClass();if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&(klass.getModifiers() & Modifier.STATIC) == 0) {Log.w(TAG, "The following Handler class should be static or leaks might occur: " +klass.getCanonicalName());}}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中有两个全局变量mLoopermQueue代表当前Handler关联的Looper和消息队列,并在构造函数中进行了初始化,重要的就是调用了:Looper.myLooper()

public static @Nullable Looper myLooper() {return sThreadLocal.get();}

其实还是调用的线程局部变量sThreadLocal,获取当前线程的Looper,这里需要注意的是,如果当前线程没有关联的Looper,这个方法会返回null。

注意:Handler在哪个线程创建的,就跟哪个线程的Looper关联,也可以在Handler的构造方法中传入指定的Looper

3.Looper.loop()循环读取消息

这个方法也在之前的文章里讲到过,核心就是一个死循环,从MessageQueue里面取消息出来交给Handler来处理。

线程消息机制的原理

看了源码之后,我们就知道了为啥在线程中需要处理消息,必须要经过以上三个步骤,且顺序不可更改

1.Looper.prepare():为当前线程准备消息队列

2.Handler默认构造方法跟当前线程中的Looper产生关联

3.Looper.loop()开启循环取消息

衍生问题

一个线程可以有几个Looper?

这个问题在刚才已经探讨了,只能有一个,不然调用Looper.prepare()会抛出运行时异常,提示“Only one Looper may be created per thread”

一个线程可以有几个Handler

可以创建无数个Handler,但是他们使用的消息队列都是同一个,也就是同一个Looper

同一个Looper是怎么区分不同的Handler的,换句话说,不同的Handler是怎么做到处理自己发出的消息的

这个问题就要来到Handler的sendMessage方法里面了,具体的流程这里不详说了,最后来到了这个方法

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;,这里就是将当前的Handler赋值给Message对象,这样在处理消息的时候通过msg.target就可以区分开不同的Handler了。处理的方法在Looper.loop中:

Looper.loop()

...
msg.target.dispatchMessage(msg);
...

顺便提一句,在Message的obtain的各种重载方法里面也有对target的赋值

Handler消息机制(二):一个线程有几个Handler相关推荐

  1. Android Framework学习(八)之Handler消息机制(Native层)解析

    在深入解析Android中Handler消息机制一文中,我们学习了Handler消息机制的java层代码,这次我们来学习Handler消息机制的native层代码. 在Java层的消息处理机制中,Me ...

  2. Handler消息机制-Native层

    Handler消息机制-Native层 android12-release Handler消息机制-FWK层 1. MessageQueue连接Native层 1.1 nativeInit初始化 Na ...

  3. 【Android】线程间通信——Handler消息机制

    文章目录 引言 Java层 永动机跑起来 示例 Looper Handler MessageQueue 永动机停下 Native层 nativeInit() nativePollOnce() nati ...

  4. Android Handler消息机制源码分析

    一,前言 众多周知, Android 只允许在主线程中更新UI,因此主线程也称为UI线程(ActivityThread). 如此设计原因有二: (1) 由于UI操作的方法都不是线程安全的,如果多个线程 ...

  5. 【安卓学习笔记】Android Handler 消息机制探究

    一.概述 1.android消息机制的含义: Android消息机制,其实指的就是 Handler 的运行机制,而 Handler 要正常运作,又需要底层的 MessageQueue , Looper ...

  6. handler消息机制入门

    handler消息机制入门 为什么要用handle? 我们在网络上读取图片信息时,是不能把耗时操作放在主线程里面的,当我们在子线程中获取到了图片的消息的时候,我们就需要把这个数据传给主线程. 而直接使 ...

  7. Android Handler消息机制不完全解析

    1.Handler的作用 Android开发中,我们经常使用Handler进行页面的更新.例如我们需要在一个下载任务完成后,去更新我们的UI效果,因为AndroidUI操作不是线程安全的,也就意味着我 ...

  8. Android进阶知识树——Android Handler消息机制

    1.概述 在安卓程序启动时,会默认在主线程中 运行程序,那如果执行一些耗时的操作则UI就会处于阻塞状态,出现界面卡顿的现象,再者用户的多种操作,系统是如何做到一一处理的,系统又是如何管理这些任务的,答 ...

  9. Handler消息机制详解

    Handler机制是Android开发中最常见的机制,可以说贯穿整个Android,在探究Handler机制原理之前,我们先来捋一下用法 1.handler.post(Runnable) 2.hand ...

最新文章

  1. bat批处理重命名问题
  2. Android 笔记之 R 文件
  3. 如何给 SAP Spartacus Storefront 创建新的页面
  4. mysql 存储过程 查询结果 循环_在存储过程中从查询结果集中怎么循环
  5. 分布式系统架构以及 CAP 原理
  6. 修手机时创意被剽窃,男子向苹果索赔7万亿!是认真的吗?
  7. freeMarker fmpp 解析PowerDesign PDM探索
  8. Apache 如何手动安装为服务并启动运行?
  9. js或jsp 获取项目路径常用方法
  10. 【Chinapub读书会第9期】5月28日赵鑫磊带你深入解析Linux
  11. 《善用佳软:高效能人士的软件应用之道》一第2章 办公软件:核心应用,实用技巧...
  12. css在文字中间插入下划线,css实现文字自定义下划线
  13. UPC-5094 - Faulty Robot - 搜索
  14. 黑客来势汹汹,受害者能以牙还牙“黑回去”吗
  15. Axure rp9 中继器新建表格
  16. 国风虚拟人形象频频亮相,虚拟数字人为传统文化传播提供了新载体
  17. ffmpeg+dxva2 +D3D9显示 学习笔记
  18. Windows 当前所接的屏幕检测
  19. linux查看用户名
  20. 从零开始之驱动发开、linux驱动(二十九、mmap原理)

热门文章

  1. github php面试题,GitHub - johnsong261510/php_interviews: PHP 面试题汇总、剑指 Offer PHP 代码实现版本...
  2. python深浅拷贝 面试_python基础-深浅拷贝
  3. java 结构数据结构_Java 数据结构
  4. C++知识点8——函数的返回值
  5. 记录一下mathtype输入任意形式矩阵
  6. html 密码框自动填充,解决chrom浏览器input密码框自动填充
  7. python发送微信消息_用python批量发送微信消息
  8. Django搭建个人博客:渲染Markdown文章目录
  9. 监控io性能, free命令, ps命令, 查看网络状态, linux下抓包
  10. 《敏捷软件开发:原则、模式与实践(C#版.修订版)》—第1章1.4节参考文献