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

7.5 KiB
Raw Blame History

Handler机制

目录


Handler原理

Handler 作用

// Handler用于线程间通信
// 主线程 → 子线程:通过 Handler 发送消息
// 子线程 → 主线程:通过 Handler 更新 UI

Handler 架构

┌─────────┐
│ Handler │  ←─── 发送和处理消息
└────┬────┘
     │
┌────▼────┐
│ Looper  │  ←─── 消息循环
└────┬────┘
     │
┌────▼────┐
│MessageQueue│ ←─── 消息队列
└────┬────┘
     │
┌────▼────┐
│ Message │  ←─── 消息对象
└─────────┘

Looper机制

Looper 作用

// Looper消息循环器
// 从 MessageQueue 中取出消息,分发给 Handler 处理

// 主线程 Looper
Looper looper = Looper.getMainLooper();

// 子线程 Looper
class MyThread extends Thread {
    @Override
    public void run() {
        Looper.prepare(); // 创建 Looper
        Looper.loop();    // 开始循环
    }
}

Looper 原理

// 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 原理

// MessageQueue消息队列
// 使用单链表存储消息
// 按时间排序,时间早的在前面

// 消息入队
boolean enqueueMessage(Message msg, long when) {
    // 插入消息到队列
    // 按时间排序
}

// 消息出队
Message next() {
    // 取出消息
    // 如果队列为空,阻塞等待
}

消息优先级

// 消息按时间排序
// when 值小的先执行

// 立即执行
handler.sendMessage(msg); // when = 0

// 延迟执行
handler.sendMessageDelayed(msg, 1000); // when = SystemClock.uptimeMillis() + 1000

Message传递

发送消息

// 方式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);

处理消息

// 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
    }
});

消息分发流程

// 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内存泄漏

泄漏原因

// ❌ 问题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

// ✅ 解决方案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

// ✅ 解决方案2使用主线程 Looper
Handler handler = new Handler(Looper.getMainLooper());

方案3及时移除消息

@Override
protected void onDestroy() {
    super.onDestroy();
    handler.removeCallbacksAndMessages(null);
}

Handler最佳实践

1. 避免内存泄漏

// 使用静态内部类 + WeakReference
// 或使用主线程 Looper

2. 及时移除消息

@Override
protected void onDestroy() {
    super.onDestroy();
    handler.removeCallbacksAndMessages(null);
}

3. 使用 Message.obtain()

// ✅ 推荐:复用 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年