Handle

让我来解释 Handler 的核心概念:

为什么需要 Handler?

Android 规定只能在主线程(UI线程)更新UI

但耗时操作(如网络请求、文件IO)不能在主线程执行

需要一个机制在子线程和主线程之间传递消息,这就是 Handler 的主要作用

Handler 的核心组件:

Handler:消息的发送和处理者

Message:消息对象,包含要传递的信息

MessageQueue:消息队列,用于存储消息

Looper:消息循环器,不断从 MessageQueue 中取出消息并交给 Handler 处理

工作流程:

Looper 通过 ThreadLocal 确保每个线程最多只有一个 Looper 实例

主线程(UI线程)默认已经创建了 Looper,子线程需要手动创建

Handler 发送消息(Message)到 MessageQueue

Looper 不断循环从 MessageQueue 取出消息,分发给对应的 Handler 处理

与后端开发的对比:

类似于生产者-消费者模式

Handler 类似于消息的生产者和消费者

MessageQueue 类似于消息队列(如 RabbitMQ)

Looper 类似于消息队列的消费者监听器

我已经在代码示例中展示了 Handler 的基本使用方式和内部原理。您可以看到:

如何创建 Handler 并处理消息

如何在子线程中发送消息

Looper 的实现原理

MessageQueue 的消息管理机制

这种设计的优点是:

实现了线程间的安全通信

避免了线程同步的复杂性

统一了异步任务的处理方式

java 复制代码
// 1. Handler 的基本使用
public class MainActivity extends Activity {
    private Handler mHandler = new Handler(Looper.getMainLooper()) {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_UPDATE_UI:
                    // 在主线程更新UI
                    textView.setText("更新UI");
                    break;
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        // 在子线程执行耗时操作
        new Thread(new Runnable() {
            @Override
            public void run() {
                // 模拟网络请求
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                
                // 通过Handler发送消息到主线程
                Message msg = Message.obtain();
                msg.what = MSG_UPDATE_UI;
                mHandler.sendMessage(msg);
                
                // 或者使用post方法
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        // 这个代码块会在主线程执行
                        textView.setText("更新UI");
                    }
                });
            }
        }).start();
    }
}

// 2. Handler 内部原理示意
public class Looper {
    // 每个线程只能有一个Looper
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
    final MessageQueue mQueue;  // 消息队列
    
    private Looper() {
        mQueue = new MessageQueue();
    }
    
    // 为当前线程创建Looper
    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 void loop() {
        final Looper me = myLooper();
        final MessageQueue queue = me.mQueue;
        
        for (;;) {
            Message msg = queue.next(); // 可能会阻塞
            if (msg == null) {
                return;
            }
            // 分发消息到对应的Handler
            msg.target.dispatchMessage(msg);
        }
    }
}

// 3. 消息队列示意
public class MessageQueue {
    Message mMessages;  // 消息链表的头部
    
    // 取出一条消息
    Message next() {
        for (;;) {
            synchronized (this) {
                // 取出消息链表中的第一条消息
                Message msg = mMessages;
                if (msg != null) {
                    mMessages = msg.next;
                    return msg;
                }
                // 如果没有消息,就等待
                try {
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
    }
    
    // 插入一条消息
    boolean enqueueMessage(Message msg, long when) {
        synchronized (this) {
            msg.when = when;
            Message p = mMessages;
            if (p == null || when == 0 || when < p.when) {
                msg.next = p;
                mMessages = msg;
            } else {
                Message prev;
                for (;;) {
                    prev = p;
                    p = p.next;
                    if (p == null || when < p.when) {
                        break;
                    }
                }
                msg.next = p;
                prev.next = msg;
            }
            notify();  // 唤醒等待的线程
        }
        return true;
    }
}
相关推荐
Lary_Rock3 分钟前
Android 编译问题 prebuilts/clang/host/linux-x86
android·linux·运维
王江奎38 分钟前
Android FFmpeg 交叉编译全指南:NDK编译 + CMake 集成
android·ffmpeg
limingade1 小时前
手机打电话通话时如何向对方播放录制的IVR引导词声音
android·智能手机·蓝牙电话·手机提取通话声音
hepherd2 小时前
Flutter 环境搭建 (Android)
android·flutter·visual studio code
_一条咸鱼_2 小时前
揭秘 Android ListView:从源码深度剖析其使用原理
android·面试·android jetpack
_一条咸鱼_2 小时前
深入剖析 Android NestedScrollView 使用原理
android·面试·android jetpack
_一条咸鱼_2 小时前
揭秘 Android ScrollView:深入剖析其使用原理与源码奥秘
android·面试·android jetpack
_一条咸鱼_2 小时前
深入剖析 Android View:从源码探寻使用原理
android·面试·android jetpack
_一条咸鱼_2 小时前
揭秘 Android View 绘制原理:从源码剖析到极致理解
android·面试·android jetpack
_一条咸鱼_2 小时前
揭秘 Android FrameLayout:从源码深度剖析使用原理
android·面试·android jetpack