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;
    }
}
相关推荐
散人102429 分钟前
Android Test3 获取的ANDROID_ID值不同
android·unit testing
雨白41 分钟前
实现动态加载布局
android
帅得不敢出门1 小时前
Android设备推送traceroute命令进行网络诊断
android·网络
linweidong1 小时前
android手势创建及识别保姆级教程
android·屏幕适配·android面试·手势交互·安卓面经·android手势·多分辨率
byte轻骑兵2 小时前
【Bluedroid】蓝牙启动之 SMP_Init 源码解析
android·c++·smp·bluedroid
每次的天空3 小时前
Android第十四次面试总结
android·面试·职场和发展
androidwork3 小时前
Android 布局优化:掌握 <include> 与 <merge> 的实战技巧
android
Jiaberrr4 小时前
uniapp 安卓 APP 后台持续运行(保活)的尝试办法
android·前端·javascript·uni-app·app·保活
gfgfgg0014 小时前
谷歌地图手机版(Google maps)v11.152.0100安卓版 - 前端工具导航
android·智能手机
清霜之辰4 小时前
安卓Compose实现鱼骨加载中效果
android