Handler 中的 handleMessage 所在线程是由什么决定的?
大多数情况下,handleMessage
所在线程和 handler 初始化所在的线程相同,但 handler 初始化的时候可以传入一个 Looper 对象,此时handleMessage
所在线程和参数looper
所在线程相同。
1. 含参构造public Handler(Looper looper)
class MainActivity : AppCompatActivity() {var handler: Handler? = nullvar looper: Looper? = nulloverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)looper = Looper.getMainLooper()val thread = object : Thread() {override fun run() {super.run()Log.e("abc", "--- Runnable:threadName ---" + Thread.currentThread().name)handler = object : Handler(looper) {override fun handleMessage(msg: Message?) {super.handleMessage(msg)Log.e("abc","--- handleMessage:threadName ---" + Thread.currentThread().name)}}}}thread.start()myBtn.setOnClickListener {val msg = Message()handler!!.sendMessage(msg)}}
}// log 打印情况
--- Runnable:threadName ---Thread-2
--- handleMessage:threadName ---main
从 log 中可以看到 handler 初始化所在线程在 Thread-2,而handleMessage
所在的线程是主线程main
.
2. 无参构造
如果使用无参的 Handler 初始化构造,需要手动调用Looper.prepare()
和Looper.loop()
:
val thread = object : Thread() {override fun run() {super.run()Log.e("abc", "--- Runnable:threadName ---" + Thread.currentThread().name)Looper.prepare()handler = object : Handler() {override fun handleMessage(msg: Message?) {super.handleMessage(msg)Log.e("abc", "--- handleMessage:threadName ---" + Thread.currentThread().name)}}Looper.loop()}}// log 打印情况
--- Runnable:threadName ---Thread-2
--- handleMessage:threadName ---Thread-2
不手动调用Looper.prepare()
会抛出异常:
java.lang.RuntimeException: Can't create handler inside thread Thread[Thread-2,5,main] that has not called Looper.prepare()
主线程中使用 Handler:
大多数时候我们不会在子线程中初始化和使用 handler,而是在主线程中使用,此时不需要prepare()
和loop()
,因为主线程中自带一个 Looper(通过Looper.getMainLooper()
可以获取)
3. 一个线程可以有多少个 Looper?Handler 和 Looper 之间如何关联?
3.1 一个线程可以有多少个 Looper
查看Looper.prepare()
源码:
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))
:
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
Threadlocal 是一个线程内部的存储类,可以在指定线程内存储数据,数据存储以后,只有指定线程可以得到存储数据。在这里 ThreadLocal 的作用是保证了每个线程都有各自的 Looper,就是说一个线程只能有一个 Looper,关于 Threadlocal,可以看看这篇文章 Threadlocal
接下来看看创建 Looper 实例的方法new Looper(quitAllowed)
:
final MessageQueue mQueue;
final Thread mThread;
private Looper(boolean quitAllowed) {mQueue = new MessageQueue(quitAllowed);mThread = Thread.currentThread();
在构造方法里,初始化 了MessageQueue 和代表当前线程的属性 mThread.
调用
Looper.prepare()
其实就是利用 ThreadLocal 为当前的线程创建了一个独立的 Looper,这其中包含了一个消息队列
3.2 Handler 和 Looper 之间如何关联
一个线程只能有一个 Looper,但一个线程中可以创建多个 Handler,那么一个 Looper 怎么和多个 Handler 对应呢?查看源码可知,post(Runnable r)
、postDelayed(Runnable r, long delayMillis)
、postAtTime(Runnable r, long uptimeMillis)
和sendMessage
最终调用的都是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 对象的 target 属性,这样在处理消息的时候通过msg.target
就可以区分开不同的 Handler 了。
Handler 中的 handleMessage 所在线程是由什么决定的?相关推荐
- Android Handler中的handleMessage方法和post方法之源码剖析
我们都知道,在子线程中进行UI操作(更新UI控件)包括以下四种方法: 1.Handler的handlerMessage()方法. 2.Handler的post()方法. 3.View的post()方法 ...
- 安编程中使用handleMessage实现线程之间数据交互
更多最新安卓编程资料请关注微信公众号:安卓编程入门进阶 百度云原清晰度地址:http://pan.baidu.com/s/1mhS0H8O 本节课介绍HandleMessage在线程之间传递数据.由于 ...
- handler.handleMessage(msg) 和 handler.sendEmptyMessage()运行在主线程吗?
遇到问题: 1. 平时 Handler 使用方式, 1. 定义 private Handler handler = new Handler() {@Override public void hand ...
- 安卓中的几种线程间通信方式
一:Handler实现线程间的通信 andriod提供了 Handler 和 Looper 来满足线程间的通信.例如一个子线程从网络上下载了一副图片,当它下载完成后会发送消息给主线程,这个消息是通过绑 ...
- Handler 基本用法--线程间传值
Handler 作用:主要接受子线程发送的数据, 并用此数据配合主线程更新UI. 解释: 当应用程序启动时,Android首先会开启一个主线程 (也就是UI线程) , 主线程为管理界面中的UI控件,进 ...
- 掌握Android中的进程和线程
进程和线程是现代网络操作系统的核心概念.Android作为一种优秀的.承袭Linux的移动操作系统,其进程和线程的概念是开发者和安全工作人员需要深入了解的问题.本文将详细介绍Android中的进程.线 ...
- Java 中的几种线程池,你之前用对了吗,互联网 面试官 如何面试
写在最前面,我总结出了很多互联网公司的面试题及答案,并整理成了文档,以及各种学习的进阶学习资料,免费分享给大家.扫码加微信好友进[程序员面试学习交流群],免费领取.也欢迎各位一起在群里探讨技术. 好久 ...
- Android中的进程和线程
写在前面的话 一个Android应用就是一个Linux进程,每个应用在各自的进程中运行,互不干扰,比较安全. 一个应用对应一个主线程,就是通常所说的UI线程,android遵守的就是单线程模型,所以说 ...
- Android Handler中post方法与send方法的区别及使用
目录 概述 Handler使用sendMessage方法 Handler使用post方法 post方法与send方法的区别 全部代码 效果图 后记 概述 Handler机制是Android中线程通信的 ...
最新文章
- 微软宣布MySQL和PostgreSQL的Azure数据库服务正式可用
- PostgreSQL9.5和JSONB的强大功能
- vc设置按钮文字颜色
- The Best Vacation CodeForces - 1358D(贪心+尺取)
- [Spring5]IOC容器_Bean管理XML方式_注入其他类型属性
- mysql数据库怎么读文件_mysql数据库读写文件
- HTML5学习笔记之音视频标签
- 笔试错题--(字符串常量池和JVM运行时数据区)
- 计算机毕业设计最新选题汇总(持续更新)
- colspan会影响内部单元格宽度失效_封装胶残留致MEMS振动传感器失效分析
- 正确方式安装Acrobat DC(附安装包)
- 抖音返利分销模式及代理系统开发
- python的OOP机制
- 设计师必备15个超赞的配色网站,从此配色无忧!
- 【面经】2018金山WPS前端笔试题 面试题
- 蜻蜓FM回应恶意代码事件 音频行业仍将现721格局
- 美国签证申请中的行政审查制度(图)
- 机器学习中分类与聚类的本质区别
- 运维(1) Jenkinsfile+Dockerfile+Nginx实现前端Vue自动化部署
- SQL语句实现关系代数中的“除法”