Handler 在 android 程序开发中使用的非常频繁、我们知道 android 是不允许在子线程中更新 UI 的,这就需要借助 Handler 来实现
- 那么你是否想过为什么一定要这个这样子做呢?
- 而且 Handler 的内部消息处理机制究竟是什么样的呢?
- 我们了解了之后还可以做点什么事?
带着这些疑问我系统的学习了一个讲解 Handler 原理;想来想去,就先从 Handler 的几个简单的使用方法开始吧,而且在总结过程中为了方便以后快捷的查阅使用,尽量说的精炼,不牵涉到源码的追踪和解析
为什么用 handler?考虑到 java 多线程的线程安全问题, android 规定只能在 UI 线程修改 Activity 中的 UI ;为了在其他线程中可以修改 UI ,所以引入 Handler ,从其他线程传消息到 UI 线程,然后 UI 线程接受到消息时更新线程
Handler 的简单使用假设在 Activity
中处理一个耗时任务,需要更新 UI ,简单看看我们平时是怎么处理的
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main3)
// 请求网络
subThread.start()
}
override fun onDestroy() {
subThread.interrupt()
super.onDestroy()
}
private val handler by lazy(LazyThreadSafetyMode.NONE) { MyHandler() }
private val subThread by lazy(LazyThreadSafetyMode.NONE) { SubThread(handler) }
private class MyHandler : Handler() {
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
// 主线程处理逻辑,一般这里需要使用弱引用持有 Activity 实例,以免内存泄漏
}
}
private class SubThread(val handler: Handler) : Thread() {
override fun run() {
super.run()
// 耗时操作 比如做网络请求
// 网络请求完毕,咱们就得哗哗哗通知 UI 刷新了,直接直接考虑 Handler 处理,其他方案暂时不做考虑
// 第一种方法,一般这个 data 是请求结果解析的内容
handler.obtainMessage(1,data).sendToTarget()
// 第二种方法
val message = Message.obtain() // 尽量使用 Message.obtain() 初始化
message.what = 1
message.obj = data // 一般这个 data 是请求结果解析的内容
handler.sendMessage(message)
// 第三种方法
handler.post(object : Thread() {
override fun run() {
super.run()
// 处理更新操作
}
})
}
}
上述代码非常简单,因为网络请求是一个耗时任务,所以我们新开了一个线程,并在网络请求结束解析完毕后通过 Handler
来通知主线程去更新 UI,简单采用了 3 种方式,细心的小伙伴可能会发现,其实第一种和第二种方法是一样的
就是利用 Handler
来发送了一个携带了内容 Message
对象,值得一提的是:我们应该尽可能地使用 Message.obtain() 而不是 new Message() 进行 Message 的初始化,主要是 Message.obtain() 可以减少内存的申请;所有方法最终都会调用这个方法:
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;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
handler 用法
Message 可携带的数据
//通常作标志位,作区分
message.what;(int)
//携带简单数据
message.arg1;(int)
message.arg2;(int)
//携带object数据类型
message.obj;(object)
handler 可以分发 Message 对象和 Runnable 对象到主线程中, 每个 Handler 实例,都会绑定到创建他的线程中(一般是位于主线程),它有两个作用:
- 安排消息或 Runnable 在某个主线程中某个地方执行;
- 安排一个动作在不同的线程中执行
Handler 中分发消息的一些方法
post(Runnable)
postAtTime(Runnable,long)
postDelayed(Runnable long)
sendEmptyMessage(int)
sendMessage(Message)
sendMessageAtTime(Message,long)
sendMessageDelayed(Message,long)
以上 post 类方法允许你排列一个 Runnable 对象到主线程队列中
sendMessage 类方法, 允许你安排一个带数据的Message对象到队列中,等待更新
本文 全面介绍了 Handler 的由来和在 Android 中的简单使用 , 希望大家在开发时会明白 Handler 机制的使用;所以为了是大家能够更好的学习 Handler 相关的知识点
在这里特别提供一份 Android Framework 源码学习笔记, 里面包含了这些年学习 Android 开发所遇到的 Handle 、AMS、PMS 等相关难题及其解决方案;有需要这份 Android Framework 源码学习笔记 的朋友:可以 私信 发送 “笔记” 即可 免费获取; 希望大家阅读过后,能够 查漏补缺;早日精通 Android Framework
笔记内容展示如下:
- Handler 的实现原理
- 子线程中能不能直接 new 一个 Handler ,为什么主线程可以
- Handler 导致的内存泄露原因及其解决方案
- 一个线程可以有几个 Handler ,几个 Looper ,几个 MessageQueue 对象
- Handler的post 与 sendMessage 的区别和应用场景
完整版 Android Framework 源码学习笔记获取方式:私信 发送 “笔记” 即可 免费获取
对于程序员来说,要学习的知识内容、技术有太多太多,要想不被环境淘汰就只有不断提升自己,从来都是我们去适应环境,而不是环境来适应我们
技术是无止境的,你需要对自己提交的每一行代码、使用的每一个工具负责,不断挖掘其底层原理,才能使自己的技术升华到更高的层面
加油!各位 Android 开发者们