Android Studio MQTT 使用测试 eclipse.paho.mqtt

VC MFC C++ MQTT VC编译MQTT VC调用MQTT dll eclipse-paho-mqtt

JS HTML Web端使用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来测试一下

猜你喜欢

转载自blog.csdn.net/cnicfhnui/article/details/108334690
今日推荐