Android: Handler 的用法详解

Android 中 Handler 的用法详解

Handler 是 Android 中用于线程间通信的重要机制,主要用于在不同线程之间发送和处理消息。以下是 Handler 的全面用法指南:

一、Handler 的基本原理

Handler 基于消息队列(MessageQueue)和循环器(Looper)工作,主要组成:

Message:携带数据的消息对象

MessageQueue:消息队列,存储待处理的消息

Looper:消息循环,不断从队列取出消息处理

Handler:发送和处理消息的接口

二、基本用法
1. 创建 Handler(主线程)

javascript 复制代码
// 在主线程创建Handler会自动关联主线程的Looper
Handler mainHandler = new Handler(Looper.getMainLooper()) {
    @Override
    public void handleMessage(Message msg) {
        // 处理消息
        switch (msg.what) {
            case 1:
                String text = (String) msg.obj;
                textView.setText(text);
                break;
        }
    }
};
2. 发送消息
javascript 复制代码
// 发送空消息
handler.sendEmptyMessage(1);

// 发送带what的消息
Message msg = handler.obtainMessage();
msg.what = 2;
msg.obj = "Hello Handler";
handler.sendMessage(msg);

// 延迟发送
handler.sendEmptyMessageDelayed(1, 1000); // 1秒后发送
handler.sendMessageDelayed(msg, 2000); // 2秒后发送
3. 在子线程使用 Handler
javascript 复制代码
new Thread(() -> {
    // 为当前线程创建Looper
    Looper.prepare();
    
    Handler threadHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            // 处理子线程消息
        }
    };
    
    // 开始消息循环
    Looper.loop();
}).start();

三、Handler 的常见使用场景

1. 更新 UI
javascript 复制代码
new Thread(() -> {
    // 模拟耗时操作
    try {
        Thread.sleep(1000);
        // 通过Handler发送消息到主线程更新UI
        Message msg = mainHandler.obtainMessage();
        msg.what = 1;
        msg.obj = "更新后的文本";
        mainHandler.sendMessage(msg);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}).start();
2. 定时任务
javascript 复制代码
// 延迟执行
handler.postDelayed(() -> {
    Toast.makeText(this, "5秒后执行", Toast.LENGTH_SHORT).show();
}, 5000);

// 循环执行
final Runnable runnable = new Runnable() {
    @Override
    public void run() {
        // 执行任务
        Log.d("Handler", "每隔1秒执行");
        // 再次post实现循环
        handler.postDelayed(this, 1000);
    }
};
handler.postDelayed(runnable, 1000);

// 取消定时任务
handler.removeCallbacks(runnable);
3. 线程间通信
javascript 复制代码
// 工作线程
class WorkerThread extends Thread {
    public Handler workerHandler;
    
    @Override
    public void run() {
        Looper.prepare();
        workerHandler = new Handler(Looper.myLooper()) {
            @Override
            public void handleMessage(Message msg) {
                // 处理来自主线程的消息
                String task = (String) msg.obj;
                Log.d("WorkerThread", "执行任务: " + task);
                
                // 可以回传结果给主线程
                Message resultMsg = mainHandler.obtainMessage();
                resultMsg.what = 2;
                resultMsg.obj = task + " 完成";
                mainHandler.sendMessage(resultMsg);
            }
        };
        Looper.loop();
    }
}

// 主线程发送任务给工作线程
WorkerThread worker = new WorkerThread();
worker.start();

// 等待workerHandler初始化
new Handler().postDelayed(() -> {
    if (worker.workerHandler != null) {
        Message msg = worker.workerHandler.obtainMessage();
        msg.obj = "下载文件";
        worker.workerHandler.sendMessage(msg);
    }
}, 1000);

四、高级用法

1. 使用 HandlerThread
javascript 复制代码
// 创建HandlerThread
HandlerThread handlerThread = new HandlerThread("MyHandlerThread");
handlerThread.start();

// 获取HandlerThread的Looper创建Handler
Handler threadHandler = new Handler(handlerThread.getLooper()) {
    @Override
    public void handleMessage(Message msg) {
        // 在后台线程处理消息
    }
};

// 发送消息
threadHandler.post(() -> {
    // 在HandlerThread中执行
});

// 退出时释放资源
handlerThread.quitSafely();
2. 避免内存泄漏
javascript 复制代码
// 使用静态内部类+弱引用
private static class SafeHandler extends Handler {
    private final WeakReference<Activity> activityRef;
    
    public SafeHandler(Activity activity) {
        super(Looper.getMainLooper());
        this.activityRef = new WeakReference<>(activity);
    }
    
    @Override
    public void handleMessage(Message msg) {
        Activity activity = activityRef.get();
        if (activity != null && !activity.isFinishing()) {
            // 安全处理消息
        }
    }
}

// 在Activity中使用
private SafeHandler safeHandler = new SafeHandler(this);
3. 使用 Message 的优化
javascript 复制代码
// 复用Message对象(推荐)
Message msg = handler.obtainMessage(WHAT_ARG, obj);
handler.sendMessage(msg);

// 设置回调代替继承Handler
handler.sendMessage(Message.obtain(handler, () -> {
    // 回调处理
}));

五、注意事项

线程安全:Handler 与创建它的线程绑定,不能跨线程直接使用

内存泄漏:非静态 Handler 内部类会持有外部类引用,Activity 销毁时要移除回调

Looper 准备:子线程使用 Handler 必须先调用 Looper.prepare()

消息堆积:避免发送过多消息导致消息队列堵塞

及时清理:在 onDestroy() 中移除所有回调

javascript 复制代码
@Override
protected void onDestroy() {
    super.onDestroy();
    handler.removeCallbacksAndMessages(null);
    if (handlerThread != null) {
        handlerThread.quitSafely();
    }
}

原文链接:https://blog.csdn.net/qq_39460057/article/details/146875072

相关推荐
千里马学框架1 天前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台1 天前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone1 天前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
致远ccc1 天前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
ttyyttemo1 天前
Kotlin 协程中的 Job 结构化并发与取消
android
sun0077001 天前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
其实防守也摸鱼1 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
AFinalStone1 天前
Android7 SystemUI 源码解析(四)NavigationBar 导航栏与 SystemBars
android·systemui
JMchen1 天前
属性动画原理与高级动画实现
android·kotlin·canvas
AFinalStone1 天前
Android7 SystemUI 源码解析(二)启动流程深度解析
android·systemui