当前位置: 首页 > article >正文

Android的Handler

1. Handler是用于线程间通信,本质上是:

Handler调用发送方法,向与Looper绑定的消息队列写入消息,然后Looper.loop()会循环的从消息队列里拿出消息。并调用dispatchMessage处理消息。而需要此消息的线程会实现回调的handleMessage接口来处理消息。

2.举个例子:主线程调用子线程的Handler发送消息。

package com.android.car.myapplication;


import static java.lang.Thread.currentThread;
import static java.lang.Thread.sleep;

import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.widget.TextView;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {

    private TextView textView;
    private Handler mainHandler;
    private Handler backgroundHandler;
    private Thread backgroundThread;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_carsetting);

        textView = findViewById(R.id.textView);

        // 主线程的 Handler,用于更新 UI
        mainHandler = new Handler(Looper.getMainLooper());

        // 创建子线程并启动它
        backgroundThread = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("childThread prepare");
                Looper.prepare();

                // 在子线程中创建一个 Handler
                // 充当其他线程调用 backgroundHandler.sendMessage/backgroundHandler.post的接收端
                backgroundHandler = new Handler(Looper.myLooper()) {
                    @Override
                    public void handleMessage(Message msg) {
                        if (msg.what == 1) {
                            System.out.println("childThread receive Msg 1");
                        }
                    }
                };

                System.out.println("childThread Looping");
                Looper.loop();
            }
        });

        backgroundThread.start();

        // 等待线程跑起来
        try {
            sleep(2000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        Message message = backgroundHandler.obtainMessage(1);
        backgroundHandler.sendMessage(message);
        System.out.println("MainThread: sendMsg 1");
    }
    
}
  • 日志 

2024-11-07 16:25:54.908 12880-12902 System.out       com...myapplication  I  childThread prepare
2024-11-07 16:25:54.908 12880-12902 System.out       com...myapplication  I  childThread Looping
2024-11-07 16:25:56.910 12880-12880 System.out       com...myapplication  I  MainThread: sendMsg 1
2024-11-07 16:25:56.912 12880-12902 System.out       com...myapplication  I  childThread receive Msg 1

3. Handler使用的源码解析 

  • 3.0 调用端使用sendMessage来发送消息
Message message = backgroundHandler.obtainMessage(1);
backgroundHandler.sendMessage(message);

追sendMessage的调用栈,最终会调用到Handler.java的enqueueMessage函数

    private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
            long uptimeMillis) {
        msg.target = this;   // 
。。。。。
        return queue.enqueueMessage(msg, uptimeMillis);
    }

1)msg.target指定了this,即当前的Handler, 对应3.3中取出消息的地方msg.target为handler, 且这个Handler是backgroundHandler。

2)enqueueMessage将msg放入了消息队列。

  • 3.1 Looper.prepare();
    public static void prepare() {
        prepare(true);
    }

    private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));
    }
  • 3.2 Handler backgroundHandler = new Handler(Looper.myLooper())
    public Handler(@NonNull Looper looper) {
        this(looper, null, false);
    }



    @UnsupportedAppUsage
    public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async) {
        this(looper, callback, async, /* shared= */ false);
    }


    public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async,
            boolean shared) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
        mIsShared = shared;
    }
  • 3.3 Looper.loop(); 关键是loopOnce()从消息队列中循环拿消息,

假设现在调用了3.0中的sendMessage方法,此时消息队列中已经有了消息。

那么调用me.mQueue.next();即可拿到这条message.

再调用dispatchMessage处理消息。

private static boolean loopOnce(final Looper me,
            final long ident, final int thresholdOverride) {
        Message msg = me.mQueue.next(); // might block
。。。。
        msg.target.dispatchMessage(msg);

。。。。。
        msg.recycleUnchecked();
。。。。。
        return true;
    }

3.0 讲过了msg.target是backgroundHandler,再往下查看dispatchMessage的实现:

    public void dispatchMessage(@NonNull Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);  // 调用者overide 实现的 handleMessage函数
        }
    }

会发现其中的handleMessage是在 2.当中实现的handleMessage方法。

4. nativePollOnce(ptr, nextPollTimeoutMillis);

nativePollOnce, 就是linux中的poll函数,可以让出线程对cpu的占用。

没有消息则线程进入空闲状态,不用一直调用来浪费cpu, 这种等待是非阻塞的。

5.总结:

在子线程中:

  • Looper.prepare()初始化了MessageQueue,与当前线程绑定。
  • Handler通过传入当前的Looper实现与Loop绑定,
  • Handler通过override实现了handleMessage。
  •  再通过Looper.loop()开启死循环来处理消息。

其他线程:

  • 调用子线程的Handler的post/sendMessage方法,来向目标线程的MessageQueue写入消息。

子线程:

  • 子线程调用Loop.loop()拿到消息,并调用dispatchMessage处理消息。
  • 在调用子线程override的handleMessage方法来处理来自其他线程的消息。

http://www.kler.cn/a/387483.html

相关文章:

  • 记录日志中logback和log4j2不能共存的问题
  • 通用项目工程的过程视图概览
  • 基于表格滚动截屏(表格全部展开,没有滚动条)
  • 华为大咖说 | 浅谈智能运维技术
  • Vue中优雅的使用Echarts的三种方式
  • 【电力系统】永磁同步电机调速系统带有扰动观测器
  • 手写Golang泛型栈和队列的库函数
  • 万字长文解读深度学习——卷积神经网络CNN
  • JS | JS中获得鼠标位置的属性有哪些?
  • 【ShuQiHere】️`adb kill-server` 和 `adb start-server` 命令的作用
  • 如何自定义一个函数有strlen的功能(不创建新的临时变量)(c基础)
  • 机器学习系列----岭回归(Ridge Regression)简介及实现
  • 【复平面】-复数相乘的几何性质
  • 从0开始深度学习(28)——序列模型
  • 在 CIFAR10 数据集上训练 Vision Transformer (ViT)
  • 解释一下Java中的异常处理机制
  • IDM扩展添加到Edge浏览器
  • 怎么给llama3.2-vision:90b模型进行量化剪枝蒸馏
  • 类加载的生命周期?
  • opencv实时弯道检测
  • 1.6K+ Star!Ichigo:一个开源的实时语音AI项目
  • 华为机试HJ29 字符串加解密
  • SDL打开YUV视频
  • AI和大模型技术在网络脆弱性扫描领域的最新进展与未来发展趋势
  • [C++ 核心编程]笔记 4.4.3 成员函数做友元
  • <<零基础C++第一期, C++入门基础>>