VC MFC C++ MQTT VC编译MQTT VC调用MQTT dll eclipse-paho-mqtt
Android Studio MQTT 使用测试 eclipse.paho.mqtt
系统:Windows10 64位
开发环境:Android Studio 4.0 64位
测试工具:MQTTBox
MQTT服务器:阿里云部署EMQX
android程序测试运行图示:
一、新建android工程
新建工程选择Empty Activity
下一步,填写工程名,包名,存储位置
二、设计界面
在activity_main.xml设计如下界面
activity_main代码:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!-- -->
<LinearLayout
android:layout_marginTop="5dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_weight="10">
<TextView
android:layout_marginTop="5dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="消息列表"
android:textColor="#468C46"/>
<TextView
android:id="@+id/textView_MQTTRevMsg"
android:layout_marginTop="5dp"
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textColor="#2196F3"/>
</LinearLayout>
<LinearLayout
android:layout_marginTop="5dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_weight="2">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="订阅列表"
android:textColor="#468C46"/>
<ListView
android:id="@+id/listview_SubscribeList"
android:layout_width="match_parent"
android:layout_height="200dp">
</ListView>
</LinearLayout>
<LinearLayout
android:layout_marginTop="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_weight="1">
<Button
android:id="@+id/btn_AddSubscribe"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="3"
android:onClick="publish"
android:text="订阅消息"
android:background="@drawable/bt_shape3"/>
<EditText
android:id="@+id/editText_AddSubscribeMsg"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:ems="10"
android:text="TestSubscribe" />
</LinearLayout>
<LinearLayout
android:layout_marginTop="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_weight="1">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="3"
android:onClick="publish"
android:text="发布点" />
<EditText
android:id="@+id/editText_Publish"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:ems="10"
android:text="device/info" />
</LinearLayout>
<LinearLayout
android:layout_marginTop="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_weight="1">
<Button
android:id="@+id/btn_SendMsg"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="3"
android:onClick="publish"
android:text="发布消息"
android:background="@drawable/bt_shape2" />
<EditText
android:id="@+id/editText_PublishMsg"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:ems="10"
android:text="testmsg!!!!" />
</LinearLayout>
</LinearLayout>
创建layout_devicelist_item.xml布局文件编写MQTT订阅列表的布局文件
layout_devicelist_item.xml代码:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/camera_item_rl"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#d7d5d5"
android:clickable="true"
android:orientation="horizontal" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:orientation="horizontal"
android:paddingLeft="5dp" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="63dp"
android:layout_marginTop="5dp"
android:orientation="horizontal"
android:paddingRight="10dp">
<TextView
android:id="@+id/camera_name_tv"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:ellipsize="end"
android:paddingLeft="5dp"
android:paddingRight="8dp"
android:singleLine="true"
android:text="camera1"
android:textColor="#333333" />
<Button
android:id="@+id/item_delete_btn"
android:layout_width="71dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:scaleType="centerInside"
android:background="@drawable/bt_shape"
android:text="删除" />
</LinearLayout>
</LinearLayout>
</RelativeLayout>
三、添加权限
在AndroidMainifest.xml中添加必须权限
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
四、添加MQTT引用
在工程build.gradle中添加MQTT的仓库引用
repositories {
maven {
url "https://repo.eclipse.org/content/repositories/paho-snapshots/" //MQTT
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:26.+'
compile 'com.android.support.constraint:constraint-layout:1.0.2'
testCompile 'junit:junit:4.12'
/*MQTT*/
compile 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.1.0'
compile 'org.eclipse.paho:org.eclipse.paho.android.service:1.1.1'
}
五、编写MQTT服务
在AndroidMainifest.xml中添加mqtt服务
<service android:name="org.eclipse.paho.android.service.MqttService" /> <!--MqttService-->
<service android:name=".MyMqttService"/> <!--MyMqttService-->
新建MQTT服务类
MyMqttService.java代码
public class MyMqttService extends Service {
public final String TAG = MyMqttService.class.getSimpleName();
private static MqttAndroidClient mqttAndroidClient;
private MqttConnectOptions mMqttConnectOptions;
public String MQTT_HOST = "tcp://www.XXXXX.vip:1883";//服务器地址(协议+地址+端口号)
public String MQTT_UserName = "admin"; // 用户名
public String MQTT_PassWord = "public"; // 密码
public int MQTT_ConnectionTimeout = 10; // 设置超时时间,单位:秒
public int KeepAliveIntervalTime = 20; // 设置心跳包发送间隔,单位:秒
public boolean CleanSession = true; // 设置是否清除缓存
public String Subscribe_Topic = "18559979152"; // 客户端订阅主题
public String EndWillMsgPublish_Topic = "EndWillMsg";// 遗嘱发布主题
public static String RESPONSE_TOPIC = "message_arrived";//响应主题
public static final String action = "com.example.cnicfhnui";//广播消息
@SuppressLint("MissingPermission")
//客户端ID,一般以客户端唯一标识符表示,这里用设备序列号表示
public String CLIENTID = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ? Build.getSerial() : Build.SERIAL;
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
init();
return super.onStartCommand(intent, flags, startId);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
// 发布消息
public static void MQTT_Publish(String Publish_Topic,Integer qos,String message) {
Boolean retained = false;// 是否在服务器保留断开连接后的最后一条消息
try {
//参数分别为:主题、消息的字节数组、服务质量、是否在服务器保留断开连接后的最后一条消息
mqttAndroidClient.publish(Publish_Topic, message.getBytes(), qos, retained.booleanValue());
} catch (MqttException e) {
e.printStackTrace();
}
}
// 订阅
public static void MQTT_Subscribe(String Publish_Topic) {
Boolean retained = false;// 是否在服务器保留断开连接后的最后一条消息
try {
mqttAndroidClient.subscribe(Publish_Topic,0);
} catch (MqttException e) {
e.printStackTrace();
}
}
// 取消订阅
public static void MQTT_UnSubscribe(String Publish_Topic) {
Boolean retained = false;// 是否在服务器保留断开连接后的最后一条消息
try {
mqttAndroidClient.unsubscribe(Publish_Topic);
} catch (MqttException e) {
e.printStackTrace();
}
}
// 初始化
private void init() {
String serverURI = MQTT_HOST; //服务器地址(协议+地址+端口号)
mqttAndroidClient = new MqttAndroidClient(this, serverURI, CLIENTID);
mqttAndroidClient.setCallback(mqttCallback); //设置监听订阅消息的回调
mMqttConnectOptions = new MqttConnectOptions();
mMqttConnectOptions.setCleanSession(CleanSession); //设置是否清除缓存
mMqttConnectOptions.setConnectionTimeout(MQTT_ConnectionTimeout); //设置超时时间,单位:秒
mMqttConnectOptions.setKeepAliveInterval(KeepAliveIntervalTime); //设置心跳包发送间隔,单位:秒
mMqttConnectOptions.setUserName(MQTT_UserName); //设置用户名
mMqttConnectOptions.setPassword(MQTT_PassWord.toCharArray()); //设置密码
// last will message
boolean doConnect = true;
String message = "{\"terminal_uid\":\"" + CLIENTID + "\",\"msg\":\"Client offline\"}";
// 最后的遗嘱
try {
mMqttConnectOptions.setWill(EndWillMsgPublish_Topic, message.getBytes(), 2, false);
} catch (Exception e) {
Log.e(TAG, "Exception Occured", e);
doConnect = false;
iMqttActionListener.onFailure(null, e);
}
if (doConnect) {
doClientConnection();
}
}
// 连接MQTT服务器
private void doClientConnection() {
if (!mqttAndroidClient.isConnected() && isConnectIsNomarl()) {
try {
mqttAndroidClient.connect(mMqttConnectOptions, null, iMqttActionListener);
} catch (MqttException e) {
e.printStackTrace();
}
}
}
// 判断网络是否连接
private boolean isConnectIsNomarl() {
ConnectivityManager connectivityManager = (ConnectivityManager) this.getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo info = connectivityManager.getActiveNetworkInfo();
if (info != null && info.isAvailable()) {
String name = info.getTypeName();
Log.i(TAG, "当前网络名称:" + name);
return true;
} else {
Log.i(TAG, "没有可用网络");
/*没有可用网络的时候,延迟3秒再尝试重连*/
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
doClientConnection();
}
}, 3000);
return false;
}
}
// MQTT是否连接成功的监听
private IMqttActionListener iMqttActionListener = new IMqttActionListener() {
@Override
public void onSuccess(IMqttToken arg0) {
Log.e(TAG, "MQTT 服务器连接成功!~ ");
try {
mqttAndroidClient.subscribe(Subscribe_Topic, 2);//订阅主题,参数:主题、服务质量
} catch (MqttException e) {
e.printStackTrace();
}
}
@Override
public void onFailure(IMqttToken arg0, Throwable arg1) {
arg1.printStackTrace();
Log.e(TAG, "MQTT 服务器连接失败!~");
doClientConnection();//连接失败,重连(可关闭服务器进行模拟)
}
};
// 订阅主题的回调
private MqttCallback mqttCallback = new MqttCallback() {
@Override
public void messageArrived(String topic, MqttMessage message) throws Exception {
Log.e(TAG, "收到消息MQTT: "+topic +" 发来的消息 :" + new String(message.getPayload()));
//收到消息,这里弹出Toast表示。如果需要更新UI,可以使用广播或者EventBus进行发送
//Toast.makeText(getApplicationContext(), "messageArrived: " + new String(message.getPayload()), Toast.LENGTH_LONG).show();
String Msg = topic +" 发来的消息 :" + new String(message.getPayload());
Intent intent = new Intent(action);
Bundle bundle = new Bundle();
bundle.putString("MQTT_RevMsg", Msg);
intent.putExtras(bundle);
sendBroadcast(intent);
}
@Override
public void deliveryComplete(IMqttDeliveryToken arg0) {
}
@Override
public void connectionLost(Throwable arg0) {
Log.e(TAG, "MQTT 服务器连接断开 ");
doClientConnection();//连接断开,重连
}
};
@Override
public void onDestroy() {
try {
mqttAndroidClient.disconnect(); //断开连接
} catch (MqttException e) {
e.printStackTrace();
}
super.onDestroy();
}
}
六、编写主程序
在mainActivity中编写代码
注册广播消息,用于接收MQTT服务发来的MQTT接收消息
// 注册广播消息接收器
IntentFilter filter = new IntentFilter(MainActivity.action);
getApplicationContext().registerReceiver(MainActivity_broadcastReceiver, filter);
广播消息接收器,把接收到的MQTT消息追加到MQTT消息列表
//广播消息接收器
public BroadcastReceiver MainActivity_broadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent msgintent) {
// TODO Auto-generated method stub
String ReceiverStr = msgintent.getExtras().getString("MQTT_RevMsg");
if(ReceiverStr==null) {
return;
}
Log.e(TAG, "MQTT接收消息:"+ReceiverStr);
textView_MQTTRevMsg.append(ReceiverStr+"\n");
offset=textView_MQTTRevMsg.getLineCount()*textView_MQTTRevMsg.getLineHeight();
if(offset>textView_MQTTRevMsg.getHeight()){
textView_MQTTRevMsg.scrollTo(0,offset-textView_MQTTRevMsg.getHeight());
}
}
};
记得在onDestroy中取消注册接收器
编写 SubscribeList_Adapter用于订阅列表适配器
/**自定义ListView适配器
* Created by cnicfhnui on 17/6/10.
*/
public class SubscribeList_Adapter extends BaseAdapter {
private Context mContext; //运行上下文
private List<Structure_SubscribeInfo> mSubscribeList = null;
private static final String TAG = "SubscribeList_Adapter";//设置输出信息名称
private OnClickListener mListener;
public Map<String, Structure_SubscribeInfo> mExecuteItemMap = null;
public void clearAll(){
mSubscribeList.clear();
notifyDataSetChanged();
}
public List<Structure_SubscribeInfo> getDeviceInfoList() {
return mSubscribeList;
}
// 自定义控件集合
public static class ViewHolder {
public TextView SubscribeName; // 设备名称
public Button DeleteBtn; // 删除按钮
}
public SubscribeList_Adapter(Context context) {
mContext = context;
mSubscribeList = new ArrayList<Structure_SubscribeInfo>();
mExecuteItemMap = new HashMap<String, Structure_SubscribeInfo>();
}
public void setOnClickListener(OnClickListener l) {
mListener = l;
}
public void addItem(Structure_SubscribeInfo item) {
mSubscribeList.add(item);
}
public void removeItem(Structure_SubscribeInfo item) {
for(int i = 0; i < mSubscribeList.size(); i++) {
if(item == mSubscribeList.get(i)) {
mSubscribeList.remove(i);
}
}
}
public void clearItem() {
//mExecuteItemMap.clear();
mSubscribeList.clear();
}
/* (non-Javadoc)
* @see android.widget.Adapter#getCount()
*/
@Override
public int getCount() {
return mSubscribeList.size();
}
/* (non-Javadoc)
* @see android.widget.Adapter#getItem(int)
*/
@Override
public Structure_SubscribeInfo getItem(int position) {
Structure_SubscribeInfo item = null;
if (position >= 0 && getCount() > position) {
item = mSubscribeList.get(position);
}
return item;
}
/* (non-Javadoc)
* @see android.widget.Adapter#getItemId(int)
*/
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return 0;
}
/* (non-Javadoc)
* @see android.widget.Adapter#getView(int, android.view.View, android.view.ViewGroup)
*/
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// 自定义视图
ViewHolder viewHolder = null;
if (convertView == null) {
viewHolder = new ViewHolder();
// 获取list_item布局文件的视图
convertView = LayoutInflater.from(mContext).inflate(R.layout.layout_devicelist_item, null);
// 获取控件对象
viewHolder.SubscribeName = (TextView) convertView.findViewById(R.id.camera_name_tv);
viewHolder.DeleteBtn = (Button) convertView.findViewById(R.id.item_delete_btn);
// 设置设备设置的监听响应函数
viewHolder.DeleteBtn.setOnClickListener(mOnClickListener);
// 设置控件集到convertView
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
// 设置position
viewHolder.DeleteBtn.setTag(position);
final Structure_SubscribeInfo deviceInfo = getItem(position);
if (deviceInfo != null){
viewHolder.SubscribeName.setText(deviceInfo.getSubscribeStr()+"-> QoS:"+deviceInfo.getQoS());// 设备名称
}
return convertView;
}
private View.OnClickListener mOnClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mListener != null) {
int position = (Integer) v.getTag();
switch (v.getId()) {
case R.id.item_delete_btn:
mListener.onDeleteClick(SubscribeList_Adapter.this, v, position);
break;
}
}
}
};
public interface OnClickListener {
public void onDeleteClick(BaseAdapter adapter, View view, int position);
}
}
编写Structure_SubscribeInfo结构体
public class Structure_SubscribeInfo {
private int id;
private int QoS;
private String SubscribeStr;
public int getID() {
return id;
}
public void setID(int id) {this.id = id;}
public int getQoS() {
return QoS;
}
public void setQoS(int QoS) {this.QoS = QoS;}
public String getSubscribeStr() {
return SubscribeStr;
}
public void setSubscribeStr(String SubscribeStr) {
this.SubscribeStr = SubscribeStr;
}
}
在MainActivity中添加
private List<Structure_SubscribeInfo> mSubscribeList = null;
private SubscribeList_Adapter mSubscribeList_Adapter = new SubscribeList_Adapter(this);
listview_SubscribeList.setAdapter(mSubscribeList_Adapter);
mSubscribeList_Adapter.setOnClickListener(new SubscribeList_Adapter.OnClickListener() {
@Override
public void onDeleteClick(BaseAdapter adapter, View view, int position) {
Log.e(TAG,"onDeleteClick:"+position);
mSubscribeList.remove(position);
MyMqttService.MQTT_UnSubscribe(mSubscribeList.get(position).getSubscribeStr());// 取消订阅
UpdateDeviceList();// 更新显示设备列表
}
});
更新订阅列表函数
// 更新显示设备列表
private void UpdateDeviceList() {
ViewGroup item = (ViewGroup) listview_SubscribeList.getChildAt(0);//此处必须为0
if(item != null){
listview_devicelist_scrolledY = item.getTop();
listview_devicelist_scrolledX = listview_SubscribeList.getFirstVisiblePosition();
}
mSubscribeList_Adapter.clearItem();
for (int i = 0; i < mSubscribeList.size(); i++) {
mSubscribeList_Adapter.addItem(mSubscribeList.get(i));
}
mSubscribeList_Adapter.notifyDataSetChanged();
listview_SubscribeList.setSelectionFromTop(listview_devicelist_scrolledX,listview_devicelist_scrolledY);
}
按钮响应方法
public void onClick(View view) {
switch (view.getId()) {
case R.id.btn_AddSubscribe:
Log.e(TAG,"btn_AddSubscribe Click:");
String AddSubscribe = editText_AddSubscribeMsg.getText().toString();
Structure_SubscribeInfo mStructure_SubscribeInfo = new Structure_SubscribeInfo();
mStructure_SubscribeInfo.setID(0);
mStructure_SubscribeInfo.setQoS(0);
mStructure_SubscribeInfo.setSubscribeStr(AddSubscribe);
mSubscribeList.add(mStructure_SubscribeInfo);
MyMqttService.MQTT_Subscribe(AddSubscribe);// 订阅消息
UpdateDeviceList();// 更新显示设备列表
break;
case R.id.btn_SendMsg:
Log.e(TAG,"btn_SendMsg Click:");
String PublishStr = editText_Publish.getText().toString();
String SendMsgStr = editText_PublishMsg.getText().toString();
MyMqttService.MQTT_Publish(PublishStr,0,SendMsgStr);
break;
default:
break;
}
}
八、测试运行
使用MQTTBox来测试一下