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)运行状态中,也能看到来自两个客户端的连接,
在服务器日志中,我们清晰的看到客户端的连接,以及订阅和发布操作。