You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin开发Android应用连接HiveMQ时whenComplete未执行求助

问题描述

用Kotlin开发Android应用,通过HiveMQ发布消息给ESP8266,参考官方文档适配代码后,调试日志始终不打印,推测whenComplete回调从未执行。代码如下:

val builder = MqttClient.builder()
    .identifier(UUID.randomUUID().toString())
    .serverHost("server.hivemq.cloud")
    .serverPort(8883)
    .sslWithDefaultConfig();

val client = builder.useMqttVersion5().buildAsync();

client.connectWith()
    .simpleAuth()
    .username("username")
    .password("password".toByteArray())
    .applySimpleAuth()
    .send()
    .whenComplete { connAck, throwable ->
        run {
            Log.d("TAG", "Some debug string");
            if (throwable != null) {
                Toast.makeText(
                    context,
                    "Unable to connect to HiveMQ servers!!",
                    Toast.LENGTH_LONG
                ).show();
            } else {
                client.publishWith()
                    .topic("my/topic")
                    .payload("ChopChop".toByteArray())
                    .send()
                    .whenComplete { publish, throwable ->
                        run {
                            if(throwable != null) {
                                Toast.makeText(context, "Unable to publish message!", Toast.LENGTH_LONG).show();
                            }
                            client.disconnect();
                        }
                    }
            }
        }
    }

排查线索

  • 检查网络权限:确保AndroidManifest.xml中添加互联网权限:

    <uses-permission android:name="android.permission.INTERNET" />
    

    Android 9及以上默认禁止明文流量,但HiveMQ Cloud用8883端口(SSL加密),无需额外配置usesCleartextTraffic,但权限必须存在。

  • 线程问题:whenComplete回调默认在后台线程执行,直接调用Toast.makeText会触发主线程异常,导致回调执行中断且无日志。需将UI操作切换到主线程,比如用Handler(Looper.getMainLooper()).post{ ... }包裹Toast代码。

  • 添加异常捕获:在send()后追加exceptionally方法,捕获请求发送阶段的异常(比如网络连接失败、参数错误),避免异常被直接吞掉:

    .send()
    .exceptionally { throwable ->
        Log.e("TAG", "Request failed", throwable)
        null
    }
    
  • 检查Logcat配置:确认Logcat的TAG过滤正确,没有隐藏Debug级别日志,且选择了当前应用进程。

  • SSL证书验证:设备时间不正确会导致SSL证书验证失败,检查设备系统时间是否同步。若仍有问题,可尝试自定义SSL配置(比如信任HiveMQ的证书)。

  • 客户端生命周期:client是局部变量,可能在回调执行前被GC回收,将其改为类成员变量,延长生命周期。

修正后的代码示例

import android.os.Handler
import android.os.Looper
import android.widget.Toast
import org.eclipse.paho.mqttv5.client.MqttClient
import java.util.UUID

// 将client设为类成员变量,避免被提前回收
private lateinit var client: MqttClient

fun connectAndPublish(context: Context) {
    val builder = MqttClient.builder()
        .identifier(UUID.randomUUID().toString())
        .serverHost("server.hivemq.cloud")
        .serverPort(8883)
        .sslWithDefaultConfig()

    client = builder.useMqttVersion5().buildAsync()

    client.connectWith()
        .simpleAuth()
        .username("username")
        .password("password".toByteArray())
        .applySimpleAuth()
        .send()
        .exceptionally { throwable ->
            Log.e("TAG", "Connect request failed", throwable)
            Handler(Looper.getMainLooper()).post {
                Toast.makeText(context, "Connect request failed!", Toast.LENGTH_LONG).show()
            }
            null
        }
        .whenComplete { connAck, throwable ->
            Log.d("TAG", "Connect callback triggered")
            Handler(Looper.getMainLooper()).post {
                if (throwable != null) {
                    Log.e("TAG", "Connect failed", throwable)
                    Toast.makeText(
                        context,
                        "Unable to connect to HiveMQ servers!!",
                        Toast.LENGTH_LONG
                    ).show()
                } else {
                    Log.d("TAG", "Connected successfully")
                    client.publishWith()
                        .topic("my/topic")
                        .payload("ChopChop".toByteArray())
                        .send()
                        .exceptionally { publishThrowable ->
                            Log.e("TAG", "Publish request failed", publishThrowable)
                            Handler(Looper.getMainLooper()).post {
                                Toast.makeText(context, "Publish request failed!", Toast.LENGTH_LONG).show()
                            }
                            null
                        }
                        .whenComplete { publish, publishThrowable ->
                            Handler(Looper.getMainLooper()).post {
                                if (publishThrowable != null) {
                                    Log.e("TAG", "Publish failed", publishThrowable)
                                    Toast.makeText(context, "Unable to publish message!", Toast.LENGTH_LONG).show()
                                }
                                client.disconnect()
                            }
                        }
                }
            }
        }
}

内容的提问来源于stack exchange,提问作者Gaurav Joseph

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 17:43:17