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

相关推荐
安卓理事人4 小时前
安卓LinkedBlockingQueue消息队列
android
万能的小裴同学6 小时前
Android M3U8视频播放器
android·音视频
q***57746 小时前
MySql的慢查询(慢日志)
android·mysql·adb
JavaNoober6 小时前
Android 前台服务 "Bad Notification" 崩溃机制分析文档
android
城东米粉儿7 小时前
关于ObjectAnimator
android
zhangphil8 小时前
Android渲染线程Render Thread的RenderNode与DisplayList,引用Bitmap及Open GL纹理上传GPU
android
火柴就是我9 小时前
从头写一个自己的app
android·前端·flutter
lichong95110 小时前
XLog debug 开启打印日志,release 关闭打印日志
android·java·前端
用户693717500138411 小时前
14.Kotlin 类:类的形态(一):抽象类 (Abstract Class)
android·后端·kotlin
火柴就是我11 小时前
NekoBoxForAndroid 编译libcore.aar
android