源碼解析博客推薦
https://juejin.im/post/5cd66c4af265da037516bec3
1.遇到的問題
1.1同一設備,多次創建mqtt client
在最開始的代碼實現中,發現同一個設備有兩個client。因爲我在client的定義上有增加timestamp作爲參數的一部分,而timestamp在獲取的時候是根據當前時間動態獲取的,這導致我在service多次啓動中,創建了多個client。
在mqtt的client中,一個clientID可以創建一個mqtt的連接,如果出現了兩個以上,那麼說明一定是clientID不同導致的。
1.2斷線重連導致陷入死循環
最開始設計斷線重連的時候,client調用的callback是:mqttcallback,這個回調需要手動處理斷線重連狀態。
//訂閱主題的回調【setAutomaticReconnect設置false調用該回調】
private MqttCallback mqttCallback = new MqttCallback() {
@Override
public void connectionLost(Throwable cause) {
LogUtils.d("mqtt", "mqttCallback>>連接中斷");
//doClientConnect();//再次連接,這種寫法會導致異常:不停的斷線重連
// try {
// Thread.sleep(30000);
// reConnect();
// }catch (InterruptedException e){
// e.printStackTrace();
// }catch (Exception e){
// e.printStackTrace();
// }
}
@Override
public void messageArrived(String topic, MqttMessage message) throws Exception {
LogUtils.d("mqtt", "消息獲得");
LogUtils.d("mqtt", "topic : " + topic);
LogUtils.d("mqtt", "message : " + message.toString());
}
@Override
public void deliveryComplete(IMqttDeliveryToken token) {
}
};
我在connectLost中再次做了
mqttAndroidClient.connect(mqttConnectOptions, null, mqttActionListener);
請求,這裏會出現一個情況:
如果再次連接成功,那麼mqtt會調用斷開之前的連接,並再次做新的連接,然後陷入死循環。
原因:
這是一種異常情況,就是在斷線連接之後的再次連接,創建了一個新的client,而新的client連接的時候,會導致之前的連接斷開,會執行connectionLost方法,而connectionLost方法的執行又會再次連接,導致新的client斷開,然後觸發connectionLost,就陷入死循環。而這種異常情況的來源是兩個client導致的。
所以,方法就是調用mqtt提供的斷線重連方法,而非手動去斷線重連。同時,避免創建兩個client。
代碼更改爲:
mqttConnectOptions.setAutomaticReconnect(true);//斷線重連
同時設置setCallback爲:MqttCallbackExtended
MqttCallbackExtended會在斷線重連成功之後調用
connectComplete
在方法裏面重新訂閱需要的topic,不然無法收到服務器的消息
這樣也可以解決手動重連需要做循環導致UI線程阻塞的問題。
1.3關閉close mqtt的時候導致內存泄漏
https://blog.csdn.net/hacker_crazy/article/details/103489861
目前的解決方法是退出應用不關閉mqtt的service。
1.4 MQTT斷開連接的時候調用順序:
mqttAndroidClient.close();
mqttAndroidClient.unregisterResources();
try {
if (mqttAndroidClient != null) {
// LogUtils.d("mqtt", "clientId : " + mqttAndroidClient.getClientId());
mqttAndroidClient.disconnect();
//mqttAndroidClient.close();
}
} catch (Exception e) {
e.printStackTrace();
LogUtils.d("mqtt", "exception 1 : " + e.getLocalizedMessage());
}