源碼解析部落格推薦
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());
}