Android 谈谈 Handler 那些事一、Handler是什么
转载请注明出处 作者:developerHaoz Github 地址:developerHaoz
本文的主要内容
- Handler 是什么
- Handler 的两个体系
- Message
一、Handler是什么
Handler 是 Android 中引入的一种让开发者参与处理线程中消息循环的机制,Handler直接继承自 Object,每个 Handler 都关联了一个线程,每个线程内部都维护了一个消息队列 MessageQueue,这样 Handler 实际上也就关联了一个消息队列。这样就可以通过 Handler 将 Message 和 Runnable 对象发送到该Handler所关联线程的 MessageQueue(消息队列)中,然后该消息队列一直在循环拿出一个 Message,对其进行处理,处理完之后拿出下一个 Message,继续处理
Handler 可以用来在多线程之间进行通信,在另一个线程中去更新 UI 线程中的 UI 控件只是 Handler 使用中的一种典型案例,除此之外,Handler 还可以做其他很多的事情,Handler 是 Thread 的代言人,是多线程之间通信的桥梁,通过 Handler,我们可以在一个线程中控制另一个线程去做某些事
二、Handler的两个体系
Handler 可以把一个 Message 对象或者 Runnable 对象压入到消息队列中,进而在UI线程中获取Message 或者执行 Runnable 对象,Handler 压入消息队列有两大体系,Post 和 sendMessage
- Post:Post允许把一个 Runnable 对象入队到消息队列中,它的方法有:post(Runnable)、PostAtTime(Runnable, long)、postDelayed(Runnable, long)
- sendMessage:sendMessage允许把一个包含消息数据的Message对象压入到消息队列中,它的方法有sendEmptyMessage(int)、sendMessage(Message)、sendMessageAtTime(Message, long)、sendMessageDelayed(Message, long)
从上面的各种方法可以看出,不管是 post 还是 sendMessage 都具有多种方法,它们可以设定Runnable 对象和 Message 对象被入队到消息队列中,是立即执行还是延迟执行
1、Post
对于 Handler 的 Post 方式来说,它会传递一个 Runnable 对象到消息队列中,在这个 Runnable 对象中,重写 run() 方法,一般是在这个 run() 方法中写入需要在UI线程中的操作
在 Handler 中,关于 Post 方式的方法有
方法名称 |
作用 |
---|---|
boolean post(Runnable r) |
把一个 Runnabled 入队到消息队列中,UI 线程从消息队列中取出这个对象后,立即执行 |
boolean postAtTime(Runnable r, long uptimeMills) |
把一个 Runnable 入队到消息队列中,UI线程从消息独立列中取出这个对象后,在特定的时间执行 |
boolean postDelayed(Runnable r, long delayMills) |
把一个 Runnable 入队到消息队列中,UI线程从消息队列中能够取出这个对象后,延迟delayMills秒执行 |
void removeCallbacks(Runnable r) |
从消息队列中移除一个 Runnable 对象 |
示例代码
public void onClick() {
new Thread(new Runnable() {
@Override
public void run() {
mHandler.post(new Runnable() {
@Override
public void run() {
// 将TextView的内容进行修改
mTvShowInfo.setText("This is a test");
}
});
}
}).start();
}
有一点需要注意的是,对于 Post 方式而言,它其中的 Runnable 对象的 run() 方法的代码,均执行在UI线程上
,所以如果是不能在 UI 线程上执行的操作,如网络请求之类的,一样无法使用Post方式执行
2、sendMessage
在Handler中,与Message发送消息相关的方法
方法 |
作用 |
---|---|
Message obtainMessage() |
获取一个Message对象 |
boolean sendMessage() |
发送一个Message对象到消息队列中,并在UI线程取到消息之后,立即执行 |
boolean sendMessageDelayed() |
发送一个Message对象到消息队列中,在 UI 线程取到消息后,延迟执行 |
boolean sendEmptyMessage(int what) |
发送一个空Message对象到消息队列中,并在 UI 线程取到消息之后,立即执行 |
boolean sendEmptyMessageDelayed(int what) |
发送一个空Message对象到消息队列中,并在 UI 线程取到消息之后,延迟执行 |
void removeMessage() |
从消息队列中移除一个未响应的消息 |
示例代码
new Thread(new Runnable() {
@Override
public void run() {
mHandler.post(new Runnable() {
@Override
public void run() {
String testStr = "This is a test";
Message message = Message.obtain();
message.obj = testStr;
mHandler.sendMessage(message);
}
});
}
}).start();
private Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
if (msg.what == RESULT_OK_HANDLER) {
String infoStr = (String)msg.obj;
mHandlerTvShowInfo.setText(infoStr);
}
}
};
三、Message
Handler 如果使用 sendMessage 的方式把消息入队到消息队列中,需要传递一个 Message 对象,而在 Handler,需要重写 handleMessage() 方法,用于获取工作线程中传递过来的消息,此方法运行在 UI 线程上
1、获取一个 Message 对象
一般并不推荐直接使用它的构造方法得到,而是建议通过 Message.obtain()
这个静态方法或者 Handler.obtainMessage()
获取。Message.obtain() 会从消息池中获取一个 Message 对象,如果消息池是空的,才会使用构造方法实例化一个新的 Message,这样有利用消息资源的重复利用,消息的上限为10个,Handler.obtainMessage() 具有多个重载方法,查看源码可以知道,Handler.obtainMessage() 在内部其实也是调用 Message.obtain()
public final Message obtainMessage()
{
return Message.obtain(this);
}
2、设置、获取和传递数据
Message是一个 final 类,所以不可被继承,Message 封装了线程中传递过来的消息,如果对于一般的数据,Message 提供了 getData() 和 setData 方法来获取和设置数据,其中操作的数据是一个Bundle 对象,这个 Bundle 对象提供一系列的 getXxx() 和 setXxx() 方法用于传递基本数据类型的键值对,使用起来比较简单。
示例代码
new Thread(new Runnable() {
@Override
public void run() {
mHandler.post(new Runnable() {
@Override
public void run() {
String testStr = "This is a test";
Message message = Message.obtain();
Bundle testBundle = new Bundle();
testBundle.putString(KEY_STRING, testStr);
message.setData(testBundle);
message.what = RESULT_OK_HANDLER;
mHandler.sendMessage(message);
}
});
}
}).start();
private Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
if (msg.what == RESULT_OK_HANDLER) {
String infoStr = msg.getData().getString(KEY_STRING);
mHandlerTvShowInfo.setText(infoStr);
}
}
};
而对于复杂的数据类型,如一个对象的传递就要相对复杂一些,在 Bundle 中提供了两个方法,专门用来传递对象的,但是这两个方法也有相应的限制,需要实现特定的接口,当然,一些 Android 自带的类,其实已经实现了这两个接口中的某一个,可以直接使用
- putParcelable(String key, Parcelable value):需要传递的对象类实现Parcelable接口
- putSerializable(String key, Serializable value):需要传递的对象类实现Serializable接口
还有另外一种方式在 Message 中传递对象,那就是使用 Message 自带的 obj 属性,它是一个 Object 类型,所以可以传递任意类型的对象,Message 自带的还有如下几个属性
属性 |
作用 |
---|---|
int arg1 |
参数一,用于传递不复杂的数据,复杂数据用 setData() 传递 |
int arg2 |
参数二,用于传递不复杂的数据,复杂数据用 setData() 传递 |
Object obj |
传递一个任意的对象 |
Messaenger replyTo |
是作为线程通信的时候使用 |
int what |
定义的消息码,一般用于设定消息的标志,辨别究竟是从哪里中发来的消息 |
参考: Android 中 Handler 的使用 Android -- 多线程之 Handler
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- “Hello Node.js” 这一次是你没见过的写法
- 作为DBA,你不得不掌握的压测工具
- Mac之vim普通命令使用
- selenium库的基本使用
- 高效大数据开发之 bitmap 思想的应用
- 从0到1实现一个虚拟DOM
- Xenomai XDDP example and Posix Compling
- 项目实践|基于Flink的用户行为日志分析系统
- 手把手教你用Matplotlib画一个小清新配色的商业图表
- 高并发场景下锁的使用技巧
- Struts2第四天:Struts2的拦截器和标签库
- kubernete编排技术八:使用operator管理有状态应用
- Spring第一天:Spring的概述、SpringIOC入门(XML)、Spring的Bean管理、Spring属性注入
- Flink的处理背压原理及问题-面试必备
- Spring第二天:Spring的IOC的注解方式、Spring的AOP开发(XML)