Files
mkdocs/docs/android面试/多线程与并发/Handler机制.md
2026-01-15 11:53:37 +08:00

367 lines
7.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Handler机制
## 目录
- [Handler原理](#handler原理)
- [Looper机制](#looper机制)
- [MessageQueue](#messagequeue)
- [Message传递](#message传递)
- [Handler内存泄漏](#handler内存泄漏)
- [Handler最佳实践](#handler最佳实践)
- [面试常见问题](#面试常见问题)
---
## Handler原理
### Handler 作用
```java
// Handler用于线程间通信
// 主线程 → 子线程:通过 Handler 发送消息
// 子线程 → 主线程:通过 Handler 更新 UI
```
### Handler 架构
```
┌─────────┐
│ Handler │ ←─── 发送和处理消息
└────┬────┘
┌────▼────┐
│ Looper │ ←─── 消息循环
└────┬────┘
┌────▼────┐
│MessageQueue│ ←─── 消息队列
└────┬────┘
┌────▼────┐
│ Message │ ←─── 消息对象
└─────────┘
```
---
## Looper机制
### Looper 作用
```java
// Looper消息循环器
// 从 MessageQueue 中取出消息,分发给 Handler 处理
// 主线程 Looper
Looper looper = Looper.getMainLooper();
// 子线程 Looper
class MyThread extends Thread {
@Override
public void run() {
Looper.prepare(); // 创建 Looper
Looper.loop(); // 开始循环
}
}
```
### Looper 原理
```java
// Looper.prepare()
public static void prepare() {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper());
}
// Looper.loop()
public static void loop() {
Looper me = myLooper();
MessageQueue queue = me.mQueue;
for (;;) {
Message msg = queue.next(); // 阻塞等待消息
if (msg == null) {
return;
}
msg.target.dispatchMessage(msg); // 分发消息
msg.recycleUnchecked();
}
}
```
---
## MessageQueue
### MessageQueue 原理
```java
// MessageQueue消息队列
// 使用单链表存储消息
// 按时间排序,时间早的在前面
// 消息入队
boolean enqueueMessage(Message msg, long when) {
// 插入消息到队列
// 按时间排序
}
// 消息出队
Message next() {
// 取出消息
// 如果队列为空,阻塞等待
}
```
### 消息优先级
```java
// 消息按时间排序
// when 值小的先执行
// 立即执行
handler.sendMessage(msg); // when = 0
// 延迟执行
handler.sendMessageDelayed(msg, 1000); // when = SystemClock.uptimeMillis() + 1000
```
---
## Message传递
### 发送消息
```java
// 方式1sendMessage
Message msg = Message.obtain();
msg.what = 1;
msg.obj = "Data";
handler.sendMessage(msg);
// 方式2sendMessageDelayed
handler.sendMessageDelayed(msg, 1000);
// 方式3post
handler.post(new Runnable() {
@Override
public void run() {
// 执行代码
}
});
// 方式4postDelayed
handler.postDelayed(runnable, 1000);
```
### 处理消息
```java
// Handler 处理消息
public class MyHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
// 处理消息
String data = (String) msg.obj;
break;
}
}
}
// 或使用 Callback
Handler handler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
// 处理消息
return true; // true 表示已处理,不再调用 handleMessage
}
});
```
### 消息分发流程
```java
// dispatchMessage 流程
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
// 1. 优先执行 Runnable
handleCallback(msg);
} else {
if (mCallback != null) {
// 2. 执行 Callback
if (mCallback.handleMessage(msg)) {
return;
}
}
// 3. 执行 handleMessage
handleMessage(msg);
}
}
```
---
## Handler内存泄漏
### 泄漏原因
```java
// ❌ 问题Handler 持有 Activity 引用
public class MainActivity extends AppCompatActivity {
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
// Handler 持有 Activity 的隐式引用
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
handler.postDelayed(new Runnable() {
@Override
public void run() {
// 如果 Activity 已销毁,但 Handler 还在处理消息
}
}, 10000);
}
}
```
### 解决方案
#### 方案1静态内部类 + WeakReference
```java
// ✅ 解决方案1静态内部类 + WeakReference
public class MainActivity extends AppCompatActivity {
private static class MyHandler extends Handler {
private WeakReference<MainActivity> mActivity;
MyHandler(MainActivity activity) {
mActivity = new WeakReference<>(activity);
}
@Override
public void handleMessage(Message msg) {
MainActivity activity = mActivity.get();
if (activity == null || activity.isFinishing()) {
return;
}
// 处理消息
}
}
private MyHandler handler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
handler = new MyHandler(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
handler.removeCallbacksAndMessages(null);
}
}
```
#### 方案2使用主线程 Looper
```java
// ✅ 解决方案2使用主线程 Looper
Handler handler = new Handler(Looper.getMainLooper());
```
#### 方案3及时移除消息
```java
@Override
protected void onDestroy() {
super.onDestroy();
handler.removeCallbacksAndMessages(null);
}
```
---
## Handler最佳实践
### 1. 避免内存泄漏
```java
// 使用静态内部类 + WeakReference
// 或使用主线程 Looper
```
### 2. 及时移除消息
```java
@Override
protected void onDestroy() {
super.onDestroy();
handler.removeCallbacksAndMessages(null);
}
```
### 3. 使用 Message.obtain()
```java
// ✅ 推荐:复用 Message 对象
Message msg = Message.obtain();
// ❌ 不推荐:创建新对象
Message msg = new Message();
```
---
## 面试常见问题
### Q1: Handler 的原理?
**答案:**
Handler → Looper → MessageQueue → Message
- Handler 发送消息到 MessageQueue
- Looper 从 MessageQueue 取出消息
- Handler 处理消息
### Q2: Looper 的作用?
**答案:**
- 消息循环器
- 从 MessageQueue 取出消息
- 分发给 Handler 处理
### Q3: Handler 为什么会导致内存泄漏?
**答案:**
- Handler 持有 Activity 的隐式引用
- Message 持有 Handler 的引用
- MessageQueue 持有 Message 的引用
- 如果 Handler 还有未处理的消息Activity 无法被回收
### Q4: 如何避免 Handler 内存泄漏?
**答案:**
1. 使用静态内部类 + WeakReference
2. 使用主线程 Looper
3. 及时移除消息onDestroy 中)
### Q5: Handler、Looper、MessageQueue 的关系?
**答案:**
- **Handler**:发送和处理消息
- **Looper**:消息循环,从 MessageQueue 取消息
- **MessageQueue**:消息队列,存储消息
- 一个线程只有一个 Looper一个 Looper 只有一个 MessageQueue可以有多个 Handler
---
*最后更新2024年*