MQTT的github地址是: https://github.com/mqtt/mqtt.github.io/wiki/software?id=software
在它推薦的 Servers/Brokers中就是我上一篇中提到的 Moquette,當然還有Apache ActiveMQ也是不錯的。
在客戶端推薦中,Eclipse Paho Java是Java語言的首選,phpMQTT則是PHP語言的首選。
那麼在Android開發中,我們同樣可以使用 Eclipse Paho Java,地址是: https://www.eclipse.org/paho/clients/java/
其實這個 Eclipse Paho Java對我們來講,就是一個JAR包而已,
下載地址爲:https://repo.eclipse.org/content/repositories/paho-releases/
在這裏我下載了 org.eclipse.paho.client.mqttv3-1.1.1.jar
在我們使用mqtt的時候,我們優先要保證有一個代理服務器(Moquette)在運行,且能夠訪問1883端口!
我們構建一個Android工程,實現最簡單的訂閱和發佈功能。
我們構建了兩個按鈕,一個用來訂閱,一個用來發布。
MainActivity.java 部分代碼如下:
// 代理服務器地址
public static final String HOST = "tcp://192.168.16.61:1883";
// 自定義主題
public static final String TOPIC = "richie";
// 自定義消息
public static final String CONTENT = "hello";
// 消息質量
public static final int qos = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
subscribeButton = findViewById(R.id.subscribe_button);
subscribeButton.setOnClickListener(this);
publishButton = findViewById(R.id.publish_button);
publishButton.setOnClickListener(this);
data = new ArrayList<>();
messageListview = findViewById(R.id.message_listview);
adapter = new ArrayAdapter<>(this,android.R.layout.simple_list_item_1,data);
messageListview.setAdapter(adapter);
}
@Override
public void onClick(View v) {
// 訂閱
if(v.getId() == R.id.subscribe_button){
try {
addMessage("點擊訂閱按鈕......");
SubscribeClient subscribeClient = new SubscribeClient(this);
subscribeClient.subscribe();
} catch (MqttException e){ e.printStackTrace(); }
catch(Exception e) { e.printStackTrace(); }
}
// 發佈
if(v.getId() == R.id.publish_button){
try {
addMessage("點擊發布按鈕......");
PublishClient publishClient = new PublishClient(this);
publishClient.publish();
} catch (MqttException e){ e.printStackTrace(); }
catch(Exception e) { e.printStackTrace(); }
}
}
上面的代碼比較簡單,就是點擊按鈕觸發兩個客戶端來完成訂閱和發佈功能。
我先看訂閱客戶端 SubscribeClient.java 部分代碼如下:
// 連接客戶端
private MqttClient client;
private String clientid = "subscribe_client";
// MainActivity引用
private MainActivity mainActivity = null;
// 構造方法,實例化客戶端並連接
public SubscribeClient(MainActivity mainActivity) throws MqttException {
// MainActivity引用
this.mainActivity = mainActivity;
// 構建包含連接參數的連接選擇對象
MqttConnectOptions options = new MqttConnectOptions();
// 設置Mqtt版本
options.setMqttVersion(MqttConnectOptions.MQTT_VERSION_3_1_1);
// 設置清空Session,false表示服務器會保留客戶端的連接記錄,true表示每次以新的身份連接到服務器
options.setCleanSession(false);
// 設置超時時間,單位爲秒
options.setConnectionTimeout(30);
// 設置會話心跳時間,單位爲秒,客戶端每隔10秒向服務端發送心跳包判斷客戶端是否在線
options.setKeepAliveInterval(10);
// 客戶端是否自動嘗試重新連接到服務器
options.setAutomaticReconnect(true);
// 創建MQTT客戶端併發起連接代理服務器
client = new MqttClient(MainActivity.HOST, clientid, new MemoryPersistence());
// 設置回調
client.setCallback(new PushCallback(this.mainActivity, this.clientid));
// 發起連接
client.connect(options);
}
// 訂閱指定主題
public void subscribe() throws MqttException {
client.subscribe(MainActivity.TOPIC, MainActivity.qos);
}
訂閱完成之後,接受消息實際是在回調類中實現的,也就是PushCallback,我們先看 PublishClient.java裏面:
// 連接客戶端
private MqttClient client;
private String clientid = "publish_client";
// MainActivity引用
private MainActivity mainActivity = null;
// 構造函數,實例化客戶端並連接代理服務器
public PublishClient(MainActivity mainActivity) throws MqttException {
// MainActivity引用
this.mainActivity = mainActivity;
// 構建包含連接參數的連接選擇對象
MqttConnectOptions options = new MqttConnectOptions();
// 設置Mqtt版本
options.setMqttVersion(MqttConnectOptions.MQTT_VERSION_3_1_1);
// 設置清空Session,false表示服務器會保留客戶端的連接記錄,true表示每次以新的身份連接到服務器
options.setCleanSession(false);
// 設置超時時間,單位爲秒
options.setConnectionTimeout(30);
// 設置會話心跳時間,單位爲秒,客戶端每隔10秒向服務端發送心跳包判斷客戶端是否在線
options.setKeepAliveInterval(10);
// 客戶端是否自動嘗試重新連接到服務器
options.setAutomaticReconnect(true);
// 創建MQTT客戶端併發起連接代理服務器
client = new MqttClient(MainActivity.HOST, clientid, new MemoryPersistence());
// 設置回調
client.setCallback(new PushCallback(this.mainActivity, this.clientid));
// 發起連接
client.connect(options);
}
// 發佈消息
public void publish() throws MqttException {
// 定義消息:hello
MqttMessage message = new MqttMessage();
message.setQos(MainActivity.qos);
message.setPayload(MainActivity.CONTENT.getBytes());
// 發佈消息
client.publish(MainActivity.TOPIC, message);
}
需要注意的是,發佈的主題要和訂閱的主題一致,這樣剛纔的訂閱客戶端才能收到。
雖然我們是在同一個Activity裏面即完成訂閱又發佈的功能,但是我們定義了兩個不同的客戶端,clientid是不同的。
大家可能注意到,訂閱和發佈的回調類是同一個 PushCallback,它繼承自 org.eclipse.paho.client.mqttv3.MqttCallback
// 客戶端ID
private String clientid = "";
// MainActivity引用
private MainActivity mainActivity = null;
// 構造方法
public PushCallback(MainActivity mainActivity, String clientid) {
this.mainActivity = mainActivity;
this.clientid = clientid;
}
// 在斷開連接時調用
@Override
public void connectionLost(Throwable throwable) {
System.out.println(this.clientid + "連接已斷開!");
mainActivity.addMessage(this.clientid + "連接已斷開!");
}
// 接收訂閱主題消息的回調
@Override
public void messageArrived(String topic, MqttMessage message) throws Exception {
System.out.println("接收消息主題 : " + topic);
System.out.println("接收消息Qos : " + message.getQos());
System.out.println("接收消息內容 : " + new String(message.getPayload()));
mainActivity.addMessage("接收消息內容 : " + new String(message.getPayload()));
}
// 接收發布主題消息的回調
@Override
public void deliveryComplete(IMqttDeliveryToken token) {
System.out.println("發佈消息回調:" + token.isComplete());
mainActivity.addMessage("發佈消息回調:" + token.isComplete());
}
上面繼承的方法裏面說明很清楚,一個用來判斷客戶端是否連接代理服務器(Moquette),一個用來接收消息,
一個用來做發佈消息的回調,整個工程效果如下:
同時,我們在代理服務器(Moquette)運行狀態中,也能看到來自兩個客戶端的連接,
在服務器日誌中,我們清晰的看到客戶端的連接,以及訂閱和發佈操作。
這個工程連同Jar包我已經上傳CSDN,下載地址是: https://download.csdn.net/download/konkon2012/11685143