Android MQTT通信

本文旨在构建一个条理清晰的Android MQTT通信的demo,希望能够提供一定的帮助,文末附代码

先看效果图

前言 

我相信对于大部分Android开发人员来说,MQTT服务是最大的坎

不过可以尝试在自己电脑上搭建mqtt服务,我参考的是这一篇博客:奋斗鱼 MQTT:windows最简单搭建mqtt服务端及本地客户端测试

按照博客里面的讲解逐条操作,最终我们可以在自己电脑上创建一个MQTT的服务,并且可以通过浏览器访问,如下图


 

如果我们想测试用浏览器发送消息,然后用app去接的话,可以这么来操作

其实浏览器端不一定需要连接电脑的ip,可以直接连接127.0.0.1也就是本机ip,同样可以连接到本机的MQTT服务; 

当浏览器也连接到MQTT服务之后,因为app端订阅的就是“swy”的topic的信息,所以当发布topic为“swy”的信息时,app端就可以接到消息了。

 那么服务端就算是有了,接下来就开始着手做Android客户端

1.引入依赖

    //MQTT
    implementation 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.1.0'
    implementation 'org.eclipse.paho:org.eclipse.paho.android.service:1.1.1'

2.申请权限

    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.WAKE_LOCK"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

3.注册服务

<application
        ......
        <service android:name="org.eclipse.paho.android.service.MqttService"/>
</application>

说明:

为了避免出现:
java.lang.NoClassDefFoundError: Failed resolution of: Landroid/support/v4/content/LocalBroadcastManager;

可以在gradle.properties文件中增加

android.useAndroidX=true
android.enableJetifier=true

 4.布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="20dp"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/btn_connect"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:text="建立连接" />

    <Button
        android:id="@+id/btn_subscribe"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:text="订阅Topic"
        android:textAllCaps="false" />

    <Button
        android:id="@+id/btn_echo"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:text="Echo测试"
        android:textAllCaps="false" />

    <Button
        android:id="@+id/btn_disconnect"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:text="断开连接" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:orientation="vertical">

        <ScrollView
            android:id="@+id/scroll_deal"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1">

            <TextView
                android:id="@+id/tv_deal"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="10dp"
                android:text="操作:\n"
                android:textColor="@color/black" />

        </ScrollView>

        <View
            android:layout_width="match_parent"
            android:layout_height="1dp"
            android:background="#dcdcdc" />

        <ScrollView
            android:id="@+id/scroll_record"
            android:layout_width="match_parent"
            android:layout_marginTop="5dp"
            android:layout_height="0dp"
            android:layout_weight="1">

            <TextView
                android:id="@+id/tv_record"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="记录:\n"
                android:textColor="@color/black" />

        </ScrollView>

    </LinearLayout>

    <Button
        android:id="@+id/btn_clear"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:text="清空" />

</LinearLayout>

说明:为了更方便的操作控件,使用了ViewBinding

build.gradle文件

android {
    ...

    defaultConfig {
        ...

        viewBinding{
            enabled true
        }
    }
}

5.主界面

import android.os.Bundle;
import android.util.Log;
import android.view.View;

import androidx.appcompat.app.AppCompatActivity;

import com.swy.mqttdemo.databinding.ActivityMainBinding;

import org.eclipse.paho.android.service.MqttAndroidClient;
import org.eclipse.paho.client.mqttv3.IMqttActionListener;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.IMqttToken;
import org.eclipse.paho.client.mqttv3.MqttCallbackExtended;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;

import java.text.SimpleDateFormat;
import java.util.Date;

public class MainActivity extends AppCompatActivity {
    private String TAG = "swyLog";
    private ActivityMainBinding binding;
    private MqttAndroidClient mqttAndroidClient;
    private MqttConnectOptions mqttConnectOptions;
    private String mqttUrl = "tcp://192.168.103.42:1883";
    private String clientId = "shaowangyun";
    private String topic = "swy";
    String testPubilish = "ECHO ECHO";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = ActivityMainBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());
        initMqttClient();

        binding.btnConnect.setOnClickListener(v -> {
            connect();
        });

        binding.btnSubscribe.setOnClickListener(v -> {
            subscribe();
        });

        binding.btnEcho.setOnClickListener(v -> {
            echo();
        });

        binding.btnDisconnect.setOnClickListener(v -> {
            disconnect();
        });

        binding.btnClear.setOnClickListener(v -> {
            binding.tvDeal.setText("操作:\n");
            binding.tvRecord.setText("记录:\n");
        });
    }

    private void initMqttClient() {
        mqttAndroidClient = new MqttAndroidClient(this, mqttUrl, clientId);
        mqttAndroidClient.setCallback(new MqttCallback());
        mqttConnectOptions = new MqttConnectOptions();
        mqttConnectOptions.setAutomaticReconnect(false);
    }

    private void connect() {
        if (mqttAndroidClient != null && mqttAndroidClient.isConnected()) {
            return;
        }
        Log.i(TAG,"建立连接");
        try {
            mqttAndroidClient.connect(mqttConnectOptions, null, new IMqttActionListener() {
                @Override
                public void onSuccess(IMqttToken asyncActionToken) {
                    appendStatus("连接成功");
                }

                @Override
                public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
                    appendStatus("连接失败");
                }
            });
        } catch (MqttException e) {
            Log.i(TAG, "connect Exceptions : " + e);
            e.printStackTrace();
        }
    }

    private void subscribe() {
        if (mqttAndroidClient == null || !mqttAndroidClient.isConnected()) {
            return;
        }
        Log.i(TAG,"订阅topic");
        try {
            mqttAndroidClient.subscribe(topic, 2, null, new IMqttActionListener() {
                @Override
                public void onSuccess(IMqttToken asyncActionToken) {
                    appendStatus( "订阅\""+topic+"\"成功");
                }

                @Override
                public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
                    appendStatus(topic + "订阅失败");
                }
            });
        } catch (MqttException e) {
            Log.i(TAG, "subscribe Exceptions : " + e);
            e.printStackTrace();
        }
    }

    private void echo() {
        if (mqttAndroidClient == null || !mqttAndroidClient.isConnected()) {
            return;
        }
        Log.i(TAG,"echo测试");
        MqttMessage message = new MqttMessage();
        message.setQos(2);
        message.setPayload(testPubilish.getBytes());
        try {
            mqttAndroidClient.publish(topic, message, null, new IMqttActionListener() {
                @Override
                public void onSuccess(IMqttToken asyncActionToken) {
                    appendStatus("消息发送成功");
                }

                @Override
                public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
                    appendStatus("消息发送失败");
                }
            });
        } catch (MqttException e) {
            Log.i(TAG, "echo Exceptions : " + e);
            e.printStackTrace();
        }
    }

    private void disconnect() {
        if (mqttAndroidClient == null || !mqttAndroidClient.isConnected()) {
            return;
        }
        Log.i(TAG,"断开连接");
        try {
            mqttAndroidClient.disconnect();
        } catch (MqttException e) {
            Log.i(TAG, "disconnect Exceptions : " + e);
            e.printStackTrace();
        }
    }

    public class MqttCallback implements MqttCallbackExtended {

        @Override
        public void connectComplete(boolean reconnect, String serverURI) {
            if (reconnect) {
                appendStatus("重连成功");
            } else {
                appendStatus("初始化成功");
            }
        }

        @Override
        public void connectionLost(Throwable cause) {
            appendStatus("连接断开");
        }

        @Override
        public void messageArrived(String topic, MqttMessage message) {
            appendMessage(1, new String(message.getPayload()));
            appendStatus("消息接收成功");
        }

        @Override
        public void deliveryComplete(IMqttDeliveryToken token) {
            appendMessage(0, testPubilish);
        }
    }

    private void appendStatus(String msg) {
        binding.tvDeal.append(getCurrentTime() + " " + msg + "\n");
        binding.scrollDeal.post(() -> binding.scrollDeal.fullScroll(View.FOCUS_DOWN));
        binding.scrollRecord.post(() -> binding.scrollRecord.fullScroll(View.FOCUS_DOWN));
    }

    //0:发送
    //1:接收
    private void appendMessage(int type, String msg) {
        if (0 == type) {
            binding.tvRecord.append("发送消息:" + msg + "\n");
        } else {
            binding.tvRecord.append("接收消息:" + msg + "\n");
        }
        binding.scrollDeal.post(() -> binding.scrollDeal.fullScroll(View.FOCUS_DOWN));
        binding.scrollRecord.post(() -> binding.scrollRecord.fullScroll(View.FOCUS_DOWN));
    }

    private String getCurrentTime() {
        Date currentTime = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("MM-dd HH:mm:ss");
        return sdf.format(currentTime);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        disconnect();
    }
}

至此,Android MQTT通信功能已经可以实现了,然后关于MainActivity中的方法我就不一一的讲解了,网上关于Android MQTT通信的原理以及更加详细的讲解数不胜数,我相信大家也都不厌其烦了,起码我是那样的,各种各样的大差不差的讲解,但是偏偏代码不能用,或者是过时了,好像自己学习了MQTT,但是关键的自己按照别人说的就是调不通。所以我写博客的目的就是整理出来最简单的,不说多全面多好用,就起码要能用,也算是给大家做一点微不足道的贡献。

demo源码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

邵旺运

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值