367 lines
7.5 KiB
Markdown
367 lines
7.5 KiB
Markdown
# 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
|
||
// 方式1:sendMessage
|
||
Message msg = Message.obtain();
|
||
msg.what = 1;
|
||
msg.obj = "Data";
|
||
handler.sendMessage(msg);
|
||
|
||
// 方式2:sendMessageDelayed
|
||
handler.sendMessageDelayed(msg, 1000);
|
||
|
||
// 方式3:post
|
||
handler.post(new Runnable() {
|
||
@Override
|
||
public void run() {
|
||
// 执行代码
|
||
}
|
||
});
|
||
|
||
// 方式4:postDelayed
|
||
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年*
|