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/

android mqtt 发送图片 android mqtt 源码_MQTT

android mqtt 发送图片 android mqtt 源码_发布_02

android mqtt 发送图片 android mqtt 源码_发布_03

在这里我下载了 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),一个用来接收消息,

一个用来做发布消息的回调,整个工程效果如下:

android mqtt 发送图片 android mqtt 源码_android mqtt 发送图片_04

同时,我们在代理服务器(Moquette)运行状态中,也能看到来自两个客户端的连接,

android mqtt 发送图片 android mqtt 源码_android mqtt 发送图片_05

在服务器日志中,我们清晰的看到客户端的连接,以及订阅和发布操作。