Android应用订阅AWS IoT主题失败,请求排查代码问题
从你的代码和日志来看,有几个明显的问题会导致订阅时连接断开,我来逐一拆解:
1. 订阅时错误修改主题变量(最可能的直接原因)
看你的subscribeToThing方法:
fun subscribeToThing() { if(mConnected) { Thread(Runnable { mThingsName = "$mThingsName/shadow/get/accepted" // ... 订阅逻辑 }).start() } }
你在这里直接修改了mThingsName的原值!第一次调用时,主题会变成[初始值]/shadow/get/accepted,但如果这个方法被调用多次(比如重连后再次订阅),mThingsName会被反复追加后缀,变成类似thing/shadow/get/accepted/shadow/get/accepted的无效主题。AWS IoT会因为收到无效的订阅请求而断开连接,这正好匹配你看到的"Client error when subscribing"和连接丢失日志。
修复方案:不要修改原变量,创建临时变量存储完整主题:
fun subscribeToThing() { if(mConnected) { Thread(Runnable { // 创建临时变量,保留原mThingsName的值 val fullTopic = "$mThingsName/shadow/get/accepted" var message: String? = null try { mIotDataManager.subscribeToTopic( fullTopic, AWSIotMqttQos.QOS1, object : AWSIotMqttNewMessageCallback { override fun onMessageArrived(topic: String?, data: ByteArray?) { try { message = String(data!!, Charsets.UTF_8) // 这里可以添加处理消息的逻辑 } catch (e: UnsupportedEncodingException) { Log.d("Unsupported Encoding error :$e") } } }) } catch (e: Exception) { Log.d("Subscription error :$e") } }).start() } else { Log.d("IOT Not Connected") } }
2. AttachPolicy操作的时机与冗余性
你在connectToIOT里同步调用了mAwsIOTClient.attachPolicy(mAttachedPolicyReq),但:
- 你已经提到测试阶段开放了全权限策略,这个attach操作其实是冗余的,反而可能因为网络延迟导致策略还未生效就发起连接(虽然同步调用会等待,但Cognito身份的策略同步可能有短暂延迟)。
- 更规范的做法是在Cognito身份池的角色上直接关联IoT策略,而不是在代码里动态attach,这样可以避免运行时的权限同步问题。
建议:移除代码中的attachPolicy调用,确保你的Cognito身份池的授权角色已经关联了测试用的全权限IoT策略。
3. 线程安全与连接状态判断
你的mConnected变量用来判断是否可以订阅,但要确保这个变量是在AWSIotMqttClientStatusCallback的Connected状态回调中线程安全地更新的。比如用AtomicBoolean来存储连接状态,避免竞态条件:
private val mConnected = AtomicBoolean(false) // 在回调中更新: override fun onStatusChanged( status: AWSIotMqttClientStatusCallback.AWSIotMqttClientStatus?, throwable: Throwable? ) { when (status) { AWSIotMqttClientStatusCallback.AWSIotMqttClientStatus.Connected -> { mConnected.set(true) // 可以在这里直接触发订阅,避免手动判断的时机问题 subscribeToThing() } AWSIotMqttClientStatusCallback.AWSIotMqttClientStatus.ConnectionLost -> { mConnected.set(false) } // 其他状态处理 } }
这样可以保证只有当连接真正建立后才会执行订阅,避免因为状态判断不及时导致的订阅失败。
4. MQTT配置的合理性
你设置了mIotDataManager.keepAlive = 50(50秒)和mIotDataManager.connectionStabilityTime = 100(100毫秒),connectionStabilityTime的值太小了,这个参数是用来判断连接是否稳定的时间,建议设置为3000毫秒以上,避免误判连接不稳定。
先优先修复第一个问题(主题变量被修改),这应该能解决你当前的订阅失败和连接断开问题。如果还有问题,可以检查AWS IoT控制台的日志(CloudWatch里的IoT日志),查看更详细的断开原因。
内容的提问来源于stack exchange,提问作者Ahamed Mujeeb

