- MQTT是什么?
mqtt的官方文檔
Github上有中文翻譯
https://github.com/mcxiaoke/mqtt
以上文檔均為mqtt協(xié)議的說明,沒有具體如何使用的指導(dǎo),深入研究協(xié)議的可以看。
1. Why MQTT?
某云的文檔是這樣說的

(原文鏈接
https://help.aliyun.com/document_detail/42419.html )
反正就是,如果不想用市面上的諸如環(huán)信融云等第三方IM庫,讓后臺(tái)人員買個(gè)好點(diǎn)的服務(wù)器,自己做IM。
2. 集成 MqttAndroidClient

實(shí)際上在gradle sync的時(shí)候,service包會(huì)報(bào)異常
『Error:Failed to resolve: org.eclipse.paho:org.eclipse.paho.android.service:1.1.0』
所以建議是在github上下載Android Demo,把整個(gè)service 包當(dāng)一個(gè)單獨(dú)的module,作為jar包,編譯到你的項(xiàng)目中

service里包含了client的jar包,所以就不用去sync下載了。
推薦使用:
eclipse出品Android Demo
https://github.com/eclipse/paho.mqtt.android
2.1初始化
mqtt的生命周期不應(yīng)該綁在某個(gè)activity上,建議傳getApplicationContext(),使其與整個(gè)應(yīng)用共存亡。

初始化一個(gè)mqttClient,實(shí)際上整個(gè)應(yīng)用也只需要存在一個(gè)mqttClient。
connectiOption默認(rèn)構(gòu)造器屬性,userName和password找后臺(tái)要。

自動(dòng)重連是默認(rèn)關(guān)閉的,設(shè)置開啟后,會(huì)在掉線的情況下每隔1秒請(qǐng)求一次;
設(shè)置超時(shí),setConnectionTimeout,timeout默認(rèn)是30秒;
cleanSession,默認(rèn)開啟,每斷一次,就清除這個(gè)鏈接,方便后臺(tái)管理。
經(jīng)調(diào)試,建議關(guān)閉自動(dòng)重連,在mqttCallbackExtened和MqttActionListener里做重連處理。
2.2 開始連接

client設(shè)置mqttCallbackExtened回調(diào)和MqttActionListener監(jiān)聽

mqttCallbackExtened需要實(shí)現(xiàn)的方法。這里的messageArrived貌似并未響應(yīng)接收的消息隊(duì)列。
重點(diǎn)關(guān)心以下
connectComplete

如果需要保持某個(gè)會(huì)話長時(shí)間保存,那么在connectOption里setCleanSession為false,

因?yàn)闃I(yè)務(wù)要求,我這里并不需要保存長會(huì)話,斷線后就重新生成id,重新訂閱,服務(wù)器也不用管理斷線的會(huì)話,定時(shí)清理,減少后臺(tái)壓力。
connectionLost
之前有提到,不設(shè)置自動(dòng)重練,那么應(yīng)該要做手動(dòng)重連的處理。
我這里先保存了斷開連接的日志,方便查錯(cuò),然后setClientID----重新生成id用于建立新會(huì)話,5秒后請(qǐng)求連接。


同樣的,在成功后訂閱主題。
失敗,記錄日志,5秒后重連。

問題來了:
為什么不在mqttCallBackExtend的onSuccess里訂閱主題,而要在Listener里訂閱?
mqttCallBackExtend的onSuccess先被觸發(fā),
然后才走IMqttActionListener的onSuccess或onFailure
可以認(rèn)為,只有后者成功走onSuccess,整個(gè)訂閱才算成功。
或者說,mqttCallBackExtend著眼在client和服務(wù)器的連接是否成功,不管會(huì)話的建立是否成功,后者重點(diǎn)在會(huì)話的建立。(這里有點(diǎn)模糊,我有空再查查資料)
2.3訂閱主題
其實(shí)這里訂閱只需要設(shè)置IMqttMessageListener就可以了,
messageArrived方法處理接收到的消息,根據(jù)接收到的topic進(jìn)行分類處理。
此處我是用EventBus分發(fā)所有接到的消息,在fragment或者Activity里處理對(duì)應(yīng)topic


附mqtt的消息類型(messageId用來保證該條消息的唯一性,可做去重判斷)

在訂閱的時(shí)候,需要注意的是,重復(fù)訂閱相同主題沒有問題,且相比重新連接消耗低。
例子:
在保證不斷線的情況下,
A循環(huán)操作 訂閱,取消訂閱,訂閱,取消訂閱…
和循環(huán)操作 開鏈接,訂閱,取消訂閱,關(guān)連接。
同一個(gè)用戶可以同時(shí)訂閱多個(gè)主題,不同的用戶訂閱的主題不一樣,
這里采取的方案是,每訂閱一個(gè)主題topic,就把這個(gè)topic存入一個(gè)list,
取消訂閱則把該topic從list中移除,
遇到斷線需要重新連接的時(shí)候,循環(huán)訂閱該list中的主題。

當(dāng)然,mqqttClient.subscribe()提供了一次訂閱多個(gè)主題的方法,當(dāng)然也需要同時(shí)傳入多個(gè)IMqttMessageListener,這相當(dāng)于要開發(fā)者同時(shí)維護(hù)幾個(gè)list(當(dāng)然也可以寫個(gè)map)

看業(yè)務(wù)復(fù)雜度吧,這里對(duì)消息的處理比較簡單,只管接收,接到就發(fā)出去。
2.4取消訂閱

2.5釋放資源
從搭建mqtt的準(zhǔn)備工作就可以看出,我們用的eclipse這個(gè)demo,本質(zhì)上就是一個(gè)service,如果綁定的是某Activity,Activity被干掉,當(dāng)然就has leaked了。(Service被干調(diào),但連接一直保持)
順序調(diào)用client.close –》client.unRegisterResource
敲黑板:可我干嘛要釋放這個(gè)資源呢?我初始化的時(shí)候,綁定的就是整個(gè)應(yīng)用的生命周期,service一直在后臺(tái)運(yùn)行著,接收訂閱的消息,
開發(fā)者只要關(guān)心:用戶訂閱了哪個(gè)主題,又取消訂閱了哪個(gè)主題,在哪個(gè)界面處理哪個(gè)主題。



參考鏈接:
http://lilei.work/2016/02/25/Android-Performance-Patterns-s5ep10-Profile-GPU-Rendering/
http://stackoverflow.com/questions/33451381/colors-of-profile-gpu-bars-on-android-m
https://developer.android.google.cn/studio/profile/am-gpu.html