Android Handler:机制、原理与示例

Android Handler:机制、原理与示例

📱 基本示例

  1. 创建与使用主线程 Handler

public class MainActivity extends AppCompatActivity {

private Handler mHandler;

private TextView mTextView;

复制代码
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    mTextView = findViewById(R.id.text_view);
    
    // 在主线程创建 Handler
    mHandler = new Handler(Looper.getMainLooper()) {
        @Override
        public void handleMessage(@NonNull Message msg) {
            switch (msg.what) {
                case 1:
                    mTextView.setText("收到消息:" + msg.obj);
                    break;
            }
        }
    };
    
    // 启动子线程发送消息
    new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                Thread.sleep(2000);
                
                Message msg = Message.obtain();
                msg.what = 1;
                msg.obj = "来自子线程的消息";
                mHandler.sendMessage(msg);
                
                // 或使用便捷方式
                mHandler.post(() -> {
                    mTextView.setText("通过 post 更新 UI");
                });
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }).start();
}

}

  1. 创建与使用子线程 Handler

    public class MainActivity extends AppCompatActivity {

    private HandlerThread handlerThread;

    private Handler handler;

    @Override

    protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_main);

    复制代码
     // 创建 HandlerThread
     handlerThread = new HandlerThread("MyHandlerThread");
     handlerThread.start();
     
     // 创建 Handler(关联到 HandlerThread 的 Looper)
     handler = new Handler(handlerThread.getLooper()) {
         @Override
         public void handleMessage(Message msg) {
             // 在子线程执行
             Log.d("Handler", "处理消息: " + msg.what);
         }
     };
     
     // 发送任务
     handler.post(new Runnable() {
         @Override
         public void run() {
             // 在 HandlerThread 中执行
             Log.d("Handler", "执行任务");
         }
     });

    }

    @Override

    protected void onDestroy() {

    super.onDestroy();

    // 退出消息循环

    if (handlerThread != null) {

    handlerThread.quitSafely();

    }

    }

    }

// 创建子线程

new Thread(new Runnable() {

@Override

public void run() {

// 1. 初始化 Looper

Looper.prepare();

复制代码
    // 2. 创建 Handler
    Handler handler = new Handler(Looper.myLooper()) {
        @Override
        public void handleMessage(Message msg) {
            // 处理消息
            Log.d("Handler", "收到消息: " + msg.what);
        }
    };
    
    // 3. 启动消息循环
    Looper.loop();
}

}).start();

  1. 定时任务示例

// 延迟执行

mHandler.postDelayed(() -> {

Log.d("Handler", "3秒后执行");

}, 3000);

// 循环执行

private Runnable mUpdateTask = new Runnable() {

@Override

public void run() {

updateUI();

// 每1秒执行一次

mHandler.postDelayed(this, 1000);

}

};

// 开始循环

mHandler.post(mUpdateTask);

// 停止循环(重要!防止内存泄漏)

@Override

protected void onDestroy() {

super.onDestroy();

mHandler.removeCallbacks(mUpdateTask);

}

说明

.获取looper的方式

Looper.getMainLooper():始终返回主线程的 Looper

Looper.myLooper():获取当前线程的 Looper,可能返回 null

handler.getLooper()

handlerThread.getLooper()

.一个handler对应一个Looper,一个Looper可以对应多个handler

🔧 核心机制

Handler 四件套

┌─────────────────────────────────────────┐

│ MessageQueue(消息队列) │

│ ┌─────────────┬─────────────┐ │

│ │ Message1 │ Message2 │ ... │

│ └─────────────┴─────────────┘ │

└─────────────┬──────────────────────────┘

┌─────────────▼──────────────────────────┐

│ Looper(消息循环器) │

│ • 从 MessageQueue 取出消息 │

│ • 分发给对应的 Handler │

└─────────────┬──────────────────────────┘

┌─────────────▼──────────────────────────┐

│ Handler(消息处理器) │

│ • 发送消息到 MessageQueue │

│ • 处理 Looper 分发的消息 │

└─────────────┬──────────────────────────┘

┌─────────────▼──────────────────────────┐

│ Message(消息) │

│ • what: 消息标识 │

│ • arg1/arg2: 整型参数 │

│ • obj: 对象参数 │

│ • target: 目标 Handler │

└────────────────────────────────────────┘

🧠 工作原理

  1. 消息循环流程

// Looper.loop() 简化逻辑

public static void loop() {

final Looper me = myLooper();

final MessageQueue queue = me.mQueue;

复制代码
for (;;) {
    // 1. 从队列取消息(可能阻塞)
    Message msg = queue.next();
    if (msg == null) return;
    
    // 2. 分发给目标 Handler
    msg.target.dispatchMessage(msg);
    
    // 3. 回收消息到池中
    msg.recycleUnchecked();
}

}

  1. 消息发送与处理

// Handler.sendMessage() 流程

public boolean sendMessage(Message msg) {

return sendMessageDelayed(msg, 0);

}

public boolean sendMessageDelayed(Message msg, long delayMillis) {

// 设置消息的目标 Handler

msg.target = this;

复制代码
// 计算执行时间
if (delayMillis < 0) delayMillis = 0;
long when = SystemClock.uptimeMillis() + delayMillis;

// 入队
return queue.enqueueMessage(msg, when);

}

// 消息分发

public void dispatchMessage(Message msg) {

if (msg.callback != null) {

// 处理 Runnable

handleCallback(msg);

} else {

if (mCallback != null) {

if (mCallback.handleMessage(msg)) return;

}

// 调用 handleMessage()

handleMessage(msg);

}

}

⚙️ 关键技术点

  1. 线程绑定

// 主线程 Looper 初始化(ActivityThread.main())

public static void main(String\[\] args) {

Looper.prepareMainLooper(); // 创建主线程 Looper

ActivityThread thread = new ActivityThread();

thread.attach(false);

复制代码
if (sMainThreadHandler == null) {
    sMainThreadHandler = thread.getHandler();
}

Looper.loop();  // 开启消息循环
throw new RuntimeException("Main thread loop unexpectedly exited");

}

// 子线程使用 Handler

new Thread(() -> {

// 1. 准备 Looper

Looper.prepare();

复制代码
// 2. 创建 Handler(会自动绑定当前线程的 Looper)
Handler handler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        // 处理消息
    }
};

// 3. 开启循环
Looper.loop();

}).start();

  1. 消息池优化

// 消息池避免频繁创建对象

Message msg = Message.obtain(); // 推荐:从池中获取

// vs

Message msg = new Message(); // 不推荐:每次创建新对象

// 使用后系统自动回收

msg.recycleUnchecked();

  1. 同步屏障(Sync Barrier)

// 紧急消息处理

public int postSyncBarrier() {

return mQueue.postSyncBarrier(SystemClock.uptimeMillis());

}

// 异步消息(优先级更高)

msg.setAsynchronous(true);

mHandler.sendMessage(msg);

🚨 注意事项

  1. 内存泄漏处理

// 错误示例:匿名内部类持有 Activity 引用

private Handler mHandler = new Handler() {

@Override

public void handleMessage(Message msg) {

// 持有外部类引用

}

};

// 正确示例1:静态内部类 + 弱引用

private static class SafeHandler extends Handler {

private final WeakReference mActivity;

复制代码
public SafeHandler(Activity activity) {
    mActivity = new WeakReference<>(activity);
}

@Override
public void handleMessage(Message msg) {
    Activity activity = mActivity.get();
    if (activity != null && !activity.isFinishing()) {
        // 安全操作
    }
}

}

// 正确示例2:在 onDestroy 中清理

@Override

protected void onDestroy() {

super.onDestroy();

mHandler.removeCallbacksAndMessages(null);

}

  1. 跨线程通信

// 子线程 → 主线程

new Thread(() -> {

// 耗时操作

String result = doBackgroundWork();

复制代码
// 方式1:sendMessage
Message msg = Message.obtain(mainHandler);
msg.obj = result;
mainHandler.sendMessage(msg);

// 方式2:post(更简洁)
mainHandler.post(() -> updateUI(result));

// 方式3:runOnUiThread(Activity 中)
runOnUiThread(() -> updateUI(result));

}).start();

  1. HandlerThread 使用

// 创建自带 Looper 的工作线程

HandlerThread handlerThread = new HandlerThread("WorkerThread");

handlerThread.start();

// 获取该线程的 Handler

Handler workerHandler = new Handler(handlerThread.getLooper());

// 在工作线程执行任务

workerHandler.post(() -> {

// 在 WorkerThread 中执行

doHeavyWork();

复制代码
// 完成后通知主线程
mainHandler.post(() -> updateUI());

});

// 结束时清理

handlerThread.quitSafely();

📊 性能优化建议

  1. 消息复用:使用 Message.obtain() 而非 new Message()
  2. 及时清理:在合适的生命周期移除回调
  3. 避免过度使用:简单的定时任务可用 postDelayed,复杂调度考虑 RxJava 或 Coroutine
  4. 线程管理:使用 HandlerThread 管理后台线程的 Looper
  5. 同步屏障谨慎用:只在必要时使用异步消息

这种机制使得 Android 能够实现高效、安全的线程间通信,是 Android 异步编程的基石。

相关推荐
千里马学框架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
sun0077002 天前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
其实防守也摸鱼2 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
AFinalStone2 天前
Android7 SystemUI 源码解析(四)NavigationBar 导航栏与 SystemBars
android·systemui
JMchen2 天前
属性动画原理与高级动画实现
android·kotlin·canvas
AFinalStone2 天前
Android7 SystemUI 源码解析(二)启动流程深度解析
android·systemui