一文读懂Handler

0 阅读3分钟

1.1 Handler

1.1.1 Handler

1. Handler 组件

  • handler:负责接收和处理消息,每个 handler 会关联一个线程,并关联到该线程的消息队列
  • message:handler 传递的消息对象,在目标线程中处理
  • looper:循环读取消息队列中的 message,每个线程有且仅有一个 looper

image.png


2. 源码

1. Handler 的源码结构:

Handler 类通过持有 Looper 和 MessageQueue 实现消息的发送和处理

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);
    }
}
2. Message 的源码结构

Message 对象 封装要传递的消息,目标 handler、消息类型

public final class Message {
    public int what;
    public Object obj;
    public Handler target;
    // 其他成员变量
 
    public static Message obtain() {
        return new Message();
    }
}
3. Looper 的源码结构

Looper 在 loop 方法中不断从 MessageQueue 中取出消息,并通过 Handler 的 dispatchMessage 方法将消息分发给对应的 Handler 处理

public final class Looper {
    static final ThreadLocal<Looper> 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;
    }
}

3. Handler 的使用

  1. 创建 Handler 对象:Handler 会与当前线程的 Looper 关联
Handler handler = new Handler();

2. 发送消息:使用 Handler 的 sendMessage () 或 sendMessageDelayed () 方法发送消息到消息队列中,供处理线程处理

Message msg = handler.obtainMessage();
msg.what = 1; // 设置消息类型
msg.obj = "Hello"; // 设置消息数据
handler.sendMessage(msg); // 发送消息

3. 处理消息:在 Handler 中重写 handleMessage () 方法,用于处理接收到的消息,在 handleMessage () 方法中,可以根据不同的消息类型进行逻辑处理。通过 msg.obj 可以获取消息携带的数据

public void handleMessage(Message msg) {
    switch (msg.what) {
        case 1:
            String data = (String) msg.obj; // 获取消息数据
            // 处理消息逻辑
            break;
        // 其他消息类型的处理
    }
}

4. 在特定线程中创建 Handler 对象:有时需要在特定的线程中创建 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();

4. Handler 应用:

  • 线程间通信:通过 handler,可以将消息发送到目标线程的消息队列中,在目标线程中处理消息

UI 线程更新:

Handler handler = new Handler();
handler.post(new Runnable() {
    public void run() {
        // 在UI线程中执行任务,用于更新UI
        // 更新UI等操作
    }
});
  • 异步任务:后台线程中处理任务,再将结果发送到 UI 线程,如网络请求、文件读写场景

异步加载数据:

// 在后台线程中加载数据
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 的 postDelayed 方法延迟执行任务
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
    public void run() {
        // 延时操作,例如延时2秒后执行某个任务
        // 更新UI等操作
    }
}, 2000); // 2000毫秒的延迟