如何创建一个Looper线程,然后立即向其发送消息?

2024-02-12

我有一个工作线程位于后台,处理消息。像这样的事情:

class Worker extends Thread {

    public volatile Handler handler; // actually private, of course

    public void run() {
        Looper.prepare();
        mHandler = new Handler() { // the Handler hooks up to the current Thread
            public boolean handleMessage(Message msg) {
                // ...
            }
        };
        Looper.loop();
    }
}

从主线程(UI 线程,这并不重要)我想做这样的事情:

Worker worker = new Worker();
worker.start();
worker.handler.sendMessage(...);

问题是,这为我创造了一个美丽的竞争条件:当时worker.handler被读取后,没有办法确定工作线程已经分配给这个字段了!

我不能简单地创建Handler来自Worker的构造函数,因为构造函数运行在主线程上,所以Handler会将自己与错误的线程关联起来。

这似乎并不罕见。我可以想出几种解决方法,但它们都很丑陋:

  1. 像这样的事情:

    class Worker extends Thread {
    
        public volatile Handler handler; // actually private, of course
    
        public void run() {
            Looper.prepare();
            mHandler = new Handler() { // the Handler hooks up to the current Thread
                public boolean handleMessage(Message msg) {
                    // ...
                }
            };
            notifyAll(); // <- ADDED
            Looper.loop();
        }
    }
    

    从主线程:

    Worker worker = new Worker();
    worker.start();
    worker.wait(); // <- ADDED
    worker.handler.sendMessage(...);
    

    但这也不可靠:如果notifyAll()发生在wait(),那么我们就永远不会醒来了!

  2. 通过初始Message to the Worker的构造函数,具有run()方法发布它。临时解决方案不适用于多条消息,或者如果我们不想立即发送但稍后发送。

  3. 忙着等待,直到handler场不再是null。是的,最后的手段...

我想创建一个Handler and MessageQueueWorker线程,但这似乎不可能。最优雅的方法是什么?


最终的解决方案(减去错误检查),感谢 CommonsWare:

class Worker extends HandlerThread {

    // ...

    public synchronized void waitUntilReady() {
        d_handler = new Handler(getLooper(), d_messageHandler);
    }

}

从主线程:

Worker worker = new Worker();
worker.start();
worker.waitUntilReady(); // <- ADDED
worker.handler.sendMessage(...);

这要归功于以下语义HandlerThread.getLooper()它会阻塞直到循环器被初始化。


顺便说一句,这与我上面的解决方案 #1 类似,因为HandlerThread大致实现如下(一定喜欢开源):

public void run() {
    Looper.prepare();
    synchronized (this) {
        mLooper = Looper.myLooper();
        notifyAll();
    }
    Looper.loop();
}

public Looper getLooper() {
    synchronized (this) {
        while (mLooper == null) {
            try {
                wait();
            } catch (InterruptedException e) {
            }
        }
    }
    return mLooper;
}

关键的区别在于它不检查工作线程是否正在运行,而是实际上创建了一个循环器;这样做的方法是将循环器存储在私有字段中。好的!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何创建一个Looper线程,然后立即向其发送消息? 的相关文章

随机推荐

  • 如何使 DockPanel 中的项目扩展以适应 WPF 中的所有可用空间?

    我有一个StackPanel含有一个StackPanel和其他一些物品 首先StackPanel具有垂直方向 内部具有水平方向 里面有一个TreeView and a ListView 我希望它们能够扩展并适应窗口的宽度 这是我通过窗口设置
  • 使用 TimeTCPClient 从公共时间服务器获取时间

    我尝试使用以下代码从公共时间服务器获取时间 package aaa import java util Arrays import java util List import org apache commons net TimeTCPCli
  • list.files 的性能问题

    我正在尝试使用以下命令从 3 个网络驱动器检索文件list files这需要永远 当我使用时find在 shell 中 它会在不到 15 秒的时间内返回所有结果 system time jnk lt list files c Volumes
  • Expo 安全存储在玩笑测试中不可用

    这个问题具体是关于expo secure store and jest 目前 我在登录时使用 expo secure store 来存储我的 JWT 它在模拟器上运行时工作正常 但是在 Jest 测试中根本不起作用 令牌返回为undefin
  • C# 通用复制构造函数

    我有一个接口和两个实现该接口的类 这些类具有泛型类型 我想从一个类的实例克隆到另一个类的实例 interface IFoo stuff class Foo
  • Intellij IDEA 11:如何从 .less 编译 .css?

    如何在 intellij 中从 less 编译 css 当然这应该很容易 但它让我难住了 有人知道怎么做吗 我写了一个当 LESS 文件发生变化时 它会自动将它们编译为 CSS 您可以配置多个 LESS 目录来监视每个项目 每个目录的输出将
  • 如何将 _locale 参数添加到安全路径?

    我设置了安全设置来保护根路径下的所有内容 除了查看隐私政策的公共页面外 privacy 一切正常 security yml access control path privacy role IS AUTHENTICATED ANONYMOU
  • 设置 PEP 代理

    我一直在研究 PEP Proxy Steelskin 以便我可以为我的 Orion Context 提供一些安全层 但是 有一些问题阻碍了我的进展 我想使用 IDM 和 Keystone 全局实例 我已按照相应的指示成功安装了 pepPro
  • PHP GD imagecreatefromjpeg 无法处理大尺寸图像?

    我的项目是当我自动上传图像时我的程序将创建拇指大小 如果图片大小约为 1024x768 我的程序可以正常工作 但是当我上传大小为 1576x2379 的图片时 显示如下错误 允许的内存大小 8388608 字节已耗尽 尝试分配 1576 字
  • SwiftUI 导航到 NavigationView 堆栈的底部

    我进行了以下设置 其中父视图包含NavigationView它显示一系列页面 A B 和 C 在页面 C 上有一个隐藏导航视图的按钮 我想要它 以便当再次显示导航视图时 它会自动导航到页面 A 但是我不确定如何使用 SwiftUI 执行此操
  • d3.js:具有多个 y 轴值的数据集数组

    我是 d3 js 的初学者 所以请友善 考虑这个 jsbin 示例 http jsbin com edatol 1 edit 我有以下数据集 var dataset d3 time hour utc offset now 5 1 10 d3
  • 如何将多个文件复制到docker数据卷中

    这听起来可能微不足道 但我找不到一种简单的方法将多个文件复制到 Docker 卷的根文件夹中 我正在使用Ubuntu仙尼尔 16 04 and 泊坞窗1 12 1 例如 如果我有一个带有卷的 Ubuntu 容器 my data docker
  • 使用 Supervisord 运行 PostgreSQL

    我想在 Ubuntu 10 04 上使用 Supervisor 运行 PostgreSQL 9 1 目前 我使用 init 脚本手动启动 PostgreSQL etc init d postgresql start 根据这篇文章 http
  • 类型错误:push() 不是一个函数

    我正在尝试将一个项目推送到数组 但它不起作用 当我运行代码时 我收到此错误 未捕获的类型错误 data allItems type push 不是函数 var data allItems exp inc totals exp 0 inc 0
  • 如何在后台运行 Solr Jetty

    我正在使用 Solr 附带的 Jetty Solr 构建 并且希望在后台而不是在终端中运行它 现在我开始它java jar start jar但我希望它记录到一个文件并在服务器的后台运行 以便我可以关闭终端窗口 我确信有一些我找不到的 ja
  • 使用PyInstaller将.py和.txt文件封装成.exe文件

    我有 2 个文件想要放入 exe 文件中 其中一个文件是 py 另一个是 txt我找不到如何获取多个文件并将其转换为可执行文件 请帮忙 您应该将 txt 文件放在一个文件夹中 然后将文件夹的名称放在 标签中 pyinstaller onef
  • 使用 Javascript 访问 CSS 自定义变量

    我在 css 文件中有以下样式 galleryImages position absolute top 24px left 41px width 900px moving false 当我尝试通过 Javascript 访问它时 它返回未定
  • JMeter(活动?)FTP 到 VLTrader

    情况 我正在使用 JMeter 来加载测试我的通信应用程序 Cleo VLTrader 我是 JMeter 的新手 并且能够使 HTTP 通信工作 但不能使 FTP 工作 当我尝试使用 JMeter FTP 请求采样器时 我可以在服务器端看
  • Nodejs如何为每个请求设置内容类型标头

    我想知道如何设置标题 Content Type application json 对于每个进来的 Nodejs Express 请求 我尝试了这两行 但如果我自己不添加标头 我的调用仍然失败 app use function req res
  • 如何创建一个Looper线程,然后立即向其发送消息?

    我有一个工作线程位于后台 处理消息 像这样的事情 class Worker extends Thread public volatile Handler handler actually private of course public v