然后在代码中定义自己的Servce.例如我的叫:MQTTService
private void init() {
String uri = host;
client = new MqttAndroidClient(getApplicationContext(), uri, clientId);
// 设置MQTT监听并且接受消息
client.setCallback(mqttCallback);
conOpt = new MqttConnectOptions();
// 清除缓存
conOpt.setCleanSession(true);
// 设置超时时间,单位:秒
conOpt.setConnectionTimeout(20);
// 心跳包发送间隔,单位:秒
conOpt.setKeepAliveInterval(3 * 60);
// 用户名
conOpt.setUserName(userName);
// 密码
conOpt.setPassword(passWord.toCharArray()); //将字符串转换为字符串数组
//断开后,是否自动连接
conOpt.setAutomaticReconnect(true);
// last will message
boolean doConnect = true;
String message = "{\"clientId\":\"" + clientId + "\"}";
Log.e(getClass().getName(), "message is:" + message);
String topic = "track";
Integer qos = 1;
Boolean retained = false;
if ((!message.equals("")) || (!topic.equals(""))) {
// 最后的遗嘱
// MQTT本身就是为信号不稳定的网络设计的,所以难免一些客户端会无故的和Broker断开连接。
//当客户端连接到Broker时,可以指定LWT,Broker会定期检测客户端是否有异常。
//当客户端异常掉线时,Broker就往连接时指定的topic里推送当时指定的LWT消息。
try {
conOpt.setWill("public", message.getBytes(), 1, retained.booleanValue());
// conOpt.setWill("e-wallet", message.getBytes(), 2, retained.booleanValue());
} catch (Exception e) {
Log.e(TAG, "Exception Occured", e);
doConnect = false;
iMqttActionListener.onFailure(null, e);
}
}
if (doConnect) {
doClientConnection();
}
}
其中userName passWord和host是与后台商量一致的
前面的工作往后才能后,我们就去调用doClientConnection连接mqtt服务,为了防止重复连接我们添加一个标志位doConnect
/**
* 连接MQTT服务器
*/
private void doClientConnection() {
if (!client.isConnected()) {
try {
client.connect(conOpt, null, iMqttActionListener);
} catch (MqttException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
}
} else {
Log.e(TAG, "mqtt isConnected");
isConnectSuccess = true;
}
}
// MQTT是否连接成功
private IMqttActionListener iMqttActionListener = new IMqttActionListener() {
@Override
public void onSuccess(IMqttToken arg0) {
Log.e(TAG, "connect mqtt success");
isConnectSuccess = true;
try {
// 订阅myTopic话题
int[] qos = {1, 2, 2, 2, 2};//0:最多一次,消息会丢失和重复;1:至少一次,但消息会重复;2:只有一次,确保消息达到一次
String[] topic = {"track", "e-wallet", "e-QR", "public", "log"};
client.subscribe(topic, qos);
} catch (MqttException e) {
e.printStackTrace();
}
}
@Override
public void onFailure(IMqttToken arg0, Throwable arg1) {
Log.e(TAG, "connect mqtt fail ");
arg1.printStackTrace();
// 连接失败,重连
mqtthandler.removeMessages(0);
mqtthandler.sendEmptyMessageDelayed(0, 20000);
}
};
由于可能有断网或者网络不正常的情况,所以我写了一个Handler,用来进行连接诶失败后重复连接的操作
private MQTTHandler mqtthandler = new MQTTHandler(this);
private static class MQTTHandler extends Handler {
private WeakReference mqttServiceWeakReference;
private MQTTHandler(MQTTService mqttService) {
mqttServiceWeakReference = new WeakReference<>(mqttService);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case 0:
if (client != null) {
mqttServiceWeakReference.get().doClientConnection();
} else {
mqttServiceWeakReference.get().init();
}
break;
}
}
}
try {
if (client != null) {
Log.e("MQTT", "PublishCardData termId:" + CommonUtils.prefixString(jtbCardInfo.getTerm_id(), "0", 18));
MqttMessage mqttMessage = new MqttMessage();
mqttMessage.setQos(qos);
mqttMessage.setRetained(retained);
mqttMessage.setId(MQTTService.UPLOAD_CARD_MESSAGE_ID);
mqttMessage.setPayload(builder.build().toByteArray());
client.publish(myTopic, mqttMessage);
}
} catch (Exception e) {
e.printStackTrace();
}
发布后我们就可以在mqttCallBack回调中收到是否发布成功的信息
// MQTT监听并且接受消息
private MqttCallback mqttCallback = new MqttCallback() {
@Override
public void messageArrived(String topic, MqttMessage message) throws Exception {
String str2 = "topic:" + topic + " qos:" + message.getQos() + " retained:" + message.isRetained();
Log.e(TAG, "messageArrived:" + str2);
// if (topic.equals("track")) {
// byte[] payload = message.getPayload();
// Track.msg msg = Track.msg.parseFrom(payload);
// Log.e(TAG, "messageArrived:" + str2 + " " + msg.toString());
// }
// if (topic.equals("e-wallet")) {
// byte[] payload = message.getPayload();
// CardOrderModel.CardOrder msg = CardOrderModel.CardOrder.parseFrom(payload);
// Log.e(TAG, "messageArrived:" + str2 + " " + msg.toString());
// }
// if (topic.equals("e-QR")) {
// byte[] payload = message.getPayload();
// QrOrderModel.QrOrder msg = QrOrderModel.QrOrder.parseFrom(payload);
// Log.e(TAG, "messageArrived:" + str2 + " " + msg.toString());
// }
// if (topic.equals("public")) {
// byte[] payload = message.getPayload();
// HeartBeatTempModel.HeartBeatTemp msg = HeartBeatTempModel.HeartBeatTemp.parseFrom(payload);
Log.e(TAG, "messageArrived:" + str2 + " " + msg.toString());
// }
}
@Override
public void deliveryComplete(IMqttDeliveryToken arg0) {
try {
MqttMessage mqttMessage = arg0.getMessage();
int qos = arg0.getMessage().getQos();
boolean isComplete = arg0.isComplete();
int messageId = mqttMessage.getId();
Log.e(TAG, "deliveryComplete:" + isComplete + " Qos:" + qos + " messageid:" + messageId);
if (messageId == UPLOAD_HEART_MESSAGE_ID) {
DeviceConfigSpUtil.setMQTTForHeartTime(MQTTService.this, CommonUtils.millToDateToDay(System.currentTimeMillis()));
}
if (messageId == UPLOAD_LOG_MESSAGE_ID) {
byte[] payload = mqttMessage.getPayload();
LogModel.CLog log = LogModel.CLog.parseFrom(payload);
j++;
if (log.getIsEnd()) {
android.util.Log.e(TAG, "文件上传完成:" + log.getFileName());
if (curLog >= logFiles.size() - 1) {
Log.e(TAG, "所有log上传完成");
SpUtils.setMQTTFUploadLogTime(MQTTService.this, CommonUtils.millToDateToDay(System.currentTimeMillis()));
} else {
curLog++;
j = 0;
getData(curLog);
}
}
if (j < dataList.size()) {
publishLog();
}
}
} catch (MqttException e) {
e.printStackTrace();
} catch (InvalidProtocolBufferException e) {
e.printStackTrace();
}
}
@Override
public void connectionLost(Throwable arg0) {
// 失去连接,重连
Log.e(TAG, "connectionLost.." + arg0.getMessage() + arg0.toString());
if (client != null) {
// 连接失败,重连
mqtthandler.removeMessages(0);
mqtthandler.sendEmptyMessageDelayed(0, 20000);
}
}
};
注意: messageArrived回调表示的是服务端发布给我们的数据,如果要接收或者处理,我们可以在这个方法里实现我们的业务逻辑。deliveryComplete表示我们发布给服务器后,是否成功的回调,我们可以在此处理我们的业务逻辑。
我们在发布信息的时候,有可能发布各种不同的的信息,例如各种主题:例如我代码中的主题。那么判断
deliveryComplete中,为了判断是那一个主题发布成功了,所以我发布的时候专门在 MqttMessage中设置了一个ID,
mqttMessage.setId(MQTTService.UPLOAD_CARD_MESSAGE_ID);
这样我就可以通过这个id区判断到底是哪一个主题发布成功了,从而操作我的业务逻辑。
由于MQTT传输的时候大多是以protoBuf的格式传输的,所以我们需要交我们的实体类转化为protoBuf的格式:
转化过程如下:
1,新建一个用来创建protobuf格式数据的工程
在项目外面那一层的buid.gradle中配置protobuf的依赖:
dependencies {
dependencies {
classpath 'com.android.tools.build:gradle:3.2.1'
///**修改**:添加对protobuf插件的依赖
classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.8'
}
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
2, 在项目内部的buid.gradle中添加protobuf的依赖
3.在buid.gradle里添加protobuf的插件配置,与上面的dependencies平级
///**修改2**:增加protobuf插件编译配置
protobuf {
protoc {
artifact = 'com.google.protobuf:protoc:3.0.0'
}
plugins {
javalite {
artifact = 'com.google.protobuf:protoc-gen-javalite:3.0.0'
}
}
generateProtoTasks {
all().each { task ->
task.plugins {
javalite {}
}
}
}
}
4,在buid.gradle里定义proto的文件目录
sourceSets {
main {
// 定义proto文件目录
proto {
srcDir 'src/main/proto'
}
}
}
这个目录是根据自己项目包的构造二命名的
5,在这个目录里放入proto格式的文件
例如:
我的track.proto文件里是这样写的,其中的com.bsit.qm702.mqtt是我正式项目中,要放置生成proto文件的目录,如果你想放置到其他目录可进行相应的修改
syntax = "proto3";
option java_package = "com.bsit.qm702.mqtt";
option java_outer_classname = "Track";
// 公交车轨迹数据
message msg {
string Termid = 1;
string Posid = 2;
string Samid = 3;
string INSTACP = 4;
string longitude = 5;
string latitude = 6;
string BusLine = 7;
string speed = 8;
string Plate = 9;
string check = 10;
string Time = 11;
string Direction = 12;
string BusDirection = 13;
string Elevation = 14;
}
然后点击项目的make进行编译,编译通过后会在指定目录生成对应的proto文件的java格式的文件
然后我们就可以把这个文件copy到我们的项目里使用,主要包名要对应住。
使用的时候我们就可以调用如下方法往这个Track对象里赋值
Track.msg.Builder builder = Track.msg.newBuilder();
builder.setTermid(CommonUtils.prefixString(psamTermNo, "0", 18));
builder.setSamid(CommonUtils.prefixString(sam, "0", 20));
builder.setPosid(CommonUtils.prefixString(psamTermNo, "0", 12));
只要调用buider对应的set方法就可以赋值,其他对象也是一样的套路。这样整个MQTT协议传送数据的过程就完成了