个人介绍
光子郎.进行开发工作七年以上,目前涉及全栈领域并进行开发。会经常跟小伙伴分享前沿技术知识,java后台、web前端、移动端(Android,uniapp,小程序)相关的知识以及经验体会,不定期会有源码及框架的分享,如果你有相关的知识想要及时了解或者讨论,那么请关注光子郎.,点点文末小卡片,不定期会有免费的资源分享给大家,感谢支持~
人生格言
你要批评指点四周风景,首先你要爬上屋顶。
光子郎今天带大家详细的了解Android中的Handler机制,一篇就懂!废话少说,开整!
目录
一、引言
二、Handler机制概述
1.Handler、Message和Looper的基本概念
三、源码结构
1.Handler的源码结构:
2.Message的源码结构
3.Lopper的源码结构
4.关系和协作机制:
四、Handler的使用方法
1.创建Handler对象:
2.发送消息:
3.处理消息:
4.在特定线程中创建Handler对象:
五、Handler的线程安全性
1.创建Handler的正确方式:
2.处理消息的线程安全性:
3.确保消息的处理在正确的线程中执行:
六、Handler进阶操作
1.异步加载数据:
2.延时操作:
3.UI线程更新:
在Android开发中,消息传递和线程通信是常见的需求。而Android的Handler机制就是用来实现这种消息传递和线程通信的重要组件。它在Android应用开发中扮演着至关重要的角色。
Handler重要性:
线程间通信:Android应用通常会涉及到多个线程的并发执行,而Handler机制提供了一种简单而高效的方式来实现线程间的通信。通过Handler,我们可以将消息发送到目标线程的消息队列中,并在目标线程中处理消息,从而实现线程间的通信和协作。
异步消息处理:在Android开发中,许多任务需要在后台线程中执行,而将结果更新到UI界面上。Handler机制允许我们在后台线程中处理任务,并通过Handler将结果发送到UI线程,以便更新UI界面。这种异步消息处理的机制在保持UI的响应性和避免阻塞主线程方面起到了至关重要的作用。
定时任务处理:Handler机制还可以用于处理定时任务。我们可以使用Handler的postDelayed()方法来延迟执行代码块或发送延时消息。这对于实现定时刷新、定时执行任务等场景非常有用。
Handler应用场景:
UI更新:当后台任务完成时,通过Handler机制将结果发送到UI线程,以更新UI界面,如显示加载完成的数据、更新进度条等。
后台任务处理:通过Handler机制,可以将后台任务发送到子线程执行,避免阻塞主线程,从而保持UI的流畅性,如网络请求、文件读写等。
定时任务:使用Handler的定时任务功能,可以实现定时执行代码块或发送延时消息,如定时刷新、定时通知等。
线程间通信:通过Handler机制,在不同线程间发送消息和处理消息,实现线程间的通信和协作,如主线程和后台线程之间的通信。
Handler:
Handler是Android中的消息处理器,它负责接收和处理消息。每个Handler实例都关联一个特定的线程,并与该线程的消息队列相关联。通过Handler,我们可以发送和处理消息,实现线程间的通信和协作。
Message:
Message是Handler传递的消息对象,用于在不同线程之间传递数据。它包含了要传递的数据和附加信息,如消息类型、标志等。Message对象可以通过Handler的sendMessage()方法发送到目标线程的消息队列中,并在目标线程中被处理。
Looper:
Looper是一个消息循环器,它用于管理线程的消息队列。每个线程只能有一个Looper对象,它负责循环读取消息队列中的消息,并将消息传递给对应的Handler进行处理。Looper的工作方式是不断从消息队列中取出消息,并通过Handler的dispatchMessage()方法将消息分发给目标Handler进行处理。
工作原理:
public class Handler {
private Looper mLooper;
private MessageQueue mQueue;
public Handler() {
this(Looper.myLooper());
}
public Handler(Looper looper) {
mLooper = looper;
mQueue = looper.getQueue();
}
public void handleMessage(Message msg) {
// 处理消息的逻辑
}
public final boolean sendMessage(Message msg) {
return sendMessageDelayed(msg, 0);
}
public final boolean sendMessageDelayed(Message msg, long delayMillis) {
if (msg.target == null) {
msg.target = this;
}
return mQueue.enqueueMessage(msg, delayMillis);
}
}
public final class Message {
public int what;
public Object obj;
public Handler target;
// 其他成员变量
public static Message obtain() {
return new Message();
}
}
public final class Looper {
static final ThreadLocal sThreadLocal = new ThreadLocal<>();
MessageQueue mQueue;
private Looper() {
mQueue = new MessageQueue();
}
public static void prepare() {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper());
}
public static Looper myLooper() {
return sThreadLocal.get();
}
public static void loop() {
Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
MessageQueue queue = me.mQueue;
while (true) {
Message msg = queue.next();
if (msg == null) {
return;
}
msg.target.dispatchMessage(msg);
msg.recycle();
}
}
public MessageQueue getQueue() {
return mQueue;
}
}
loop()
方法中不断从MessageQueue中取出消息,并通过Handler的dispatchMessage()
方法将消息分发给对应的Handler进行处理。sendMessage()
或sendMessageDelayed()
方法时,会将Message对象发送到MessageQueue中,等待Looper的循环读取和处理。dispatchMessage()
方法传递给目标Handler,最终由目标Handler的handleMessage()
方法处理消息。通过以下方式创建Handler对象:
Handler handler = new Handler();
此时,Handler会与当前线程的Looper关联。
使用Handler的sendMessage()
或sendMessageDelayed()
方法发送消息到消息队列中,供处理线程处理:
Message msg = handler.obtainMessage();
msg.what = 1; // 设置消息类型
msg.obj = "Hello"; // 设置消息数据
handler.sendMessage(msg); // 发送消息
上述代码创建了一个消息对象,设置了消息类型和数据,并通过Handler的sendMessage()
方法将消息发送到消息队列中。
在Handler中重写handleMessage()
方法,用于处理接收到的消息:
public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
String data = (String) msg.obj; // 获取消息数据
// 处理消息逻辑
break;
// 其他消息类型的处理
}
}
在handleMessage()
方法中,可以根据不同的消息类型进行逻辑处理。通过msg.obj
可以获取消息携带的数据。
有时需要在特定的线程中创建Handler对象,可以通过Looper来实现。例如,在后台线程中创建Handler对象:
Handler handler;
Thread thread = new Thread(new Runnable() {
public void run() {
Looper.prepare();
handler = new Handler() {
public void handleMessage(Message msg) {
// 处理消息逻辑
}
};
Looper.loop();
}
});
thread.start();
通过在新的线程中调用Looper的prepare()
和loop()
方法,为该线程创建了一个消息循环器,然后在此循环器中创建了Handler对象。这样,该Handler就与新线程的消息队列相关联,可以接收并处理该线程中的消息。
prepare()
和loop()
方法来创建消息循环器,并确保在该线程中只有一个Looper存在。post()
或postDelayed()
方法将更新UI的任务提交到主线程执行。synchronized
:在访问Handler的关键代码块或方法上使用synchronized
关键字,以确保同一时间只有一个线程访问Handler对象。ConcurrentLinkedQueue
,来存储消息,以避免多个线程之间的竞争。post()
方法指定目标线程的Looper。总结,为了确保Handler在多线程环境下的线程安全性,需要注意以下几点:
synchronized
关键字。// 在后台线程中加载数据
Thread thread = new Thread(new Runnable() {
public void run() {
// 执行耗时操作,如网络请求或数据库查询
// 加载完成后,发送消息通知主线程
Message message = handler.obtainMessage();
message.what = LOAD_COMPLETE;
message.obj = loadedData;
handler.sendMessage(message);
}
});
thread.start();
// 主线程中处理消息
Handler handler = new Handler() {
public void handleMessage(Message msg) {
if (msg.what == LOAD_COMPLETE) {
// 处理加载完成的数据
Object data = msg.obj;
// 更新UI等操作
}
}
};
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
public void run() {
// 延时操作,例如延时2秒后执行某个任务
// 更新UI等操作
}
}, 2000); // 2000毫秒的延时
Handler handler = new Handler();
handler.post(new Runnable() {
public void run() {
// 在UI线程中执行任务,用于更新UI
// 更新UI等操作
}
});
好了,光子郎这次的Handler讲解就到这里,相信小伙伴们对Handler的理解已经进入熟练程度,希望能够在以后的开发中帮得上大家~
这次的分享就到这里,不要忘记关注光子郎,也点点文末小卡片,有JAVA和Android的面试以及学习资料免费领取,也一定会有你喜欢的资源分享以及干货整理,我们下期再见啦,拜拜~