Android中MQTT的使用_android端的mqtt必须卸载sevice里面吗-程序员宅基地

技术标签: MQTT  

Android中使用MQTT需要使用到Paho Android Service库,Paho Android Service是一个用Java编写的MQTT客户端库。
GitHub地址:https://github.com/eclipse/paho.mqtt.android

1 集成

  1. 在module的build.gradle文件中添加依赖
repositories {
    maven {
        url "https://repo.eclipse.org/content/repositories/paho-snapshots/"
    }
}
dependencies {
    compile 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.1.0'
    compile 'org.eclipse.paho:org.eclipse.paho.android.service:1.1.1'
}
  1. 在 AndroidManifest.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" />
  1. 在 AndroidManifest.xml 注册Service (MyMqttService为自己写的服务,下文会讲到)
        <service android:name="org.eclipse.paho.android.service.MqttService" /> <!--MqttService-->
        <service android:name="com.dongyk.service.MyMqttService"/> <!--MyMqttService-->

2 具体代码

2.1 Android中使用MQTT最主要的就是以下几个方法:

  • connect:连接MQTT服务器,这里主要讲3个参数的方法,如下:
 @Override
 public IMqttToken connect(MqttConnectOptions options, Object userContext,
   IMqttActionListener callback) throws MqttException {
    //...
}

参数options:用来携带连接服务器的一系列参数,例如用户名、密码等。
参数userContext:可选对象,用于向回调传递上下文。一般传null即可。
参数callback:用来监听MQTT是否连接成功的回调

  • publish:发布消息,这里使用四个参数的方法,如下:
 @Override
 public IMqttDeliveryToken publish(String topic, byte[] payload, int qos,
   boolean retained) throws MqttException, MqttPersistenceException {
    //...
 }

参数topic:发布消息的主题
参数payload:消息的字节数组
参数qos:提供消息的服务质量,可传0、1或2
参数retained:是否在服务器保留断开连接后的最后一条消息

  • subscribe:订阅消息,这里主要讲2个参数的方法,如下:
 @Override
 public IMqttToken subscribe(String topic, int qos) throws MqttException,
   MqttSecurityException {
    //...
 }

参数topic:订阅消息的主题
参数qos:订阅消息的服务质量,可传0、1或2

2.2 MQTT服务——MyMqttService

下面写一个 Service 来实现MQTT在Android运用中的connect、publish、subscribe

package com.wildma.mqttandroidclient;

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.util.Log;
import android.widget.Toast;

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.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;

/**
 * Author       wildma
 * Github       https://github.com/wildma
 * CreateDate   2018/11/08
 * Desc         ${MQTT服务}
 */

public class MyMqttService extends Service {

    public final String TAG = MyMqttService.class.getSimpleName();
    private static MqttAndroidClient  mqttAndroidClient;
    private        MqttConnectOptions mMqttConnectOptions;
    public        String HOST           = "tcp://192.168.0.102:61613";//服务器地址(协议+地址+端口号)
    public        String USERNAME       = "admin";//用户名
    public        String PASSWORD       = "password";//密码
    public static String PUBLISH_TOPIC  = "tourist_enter";//发布主题
    public static String RESPONSE_TOPIC = "message_arrived";//响应主题
    @RequiresApi(api = 26)
    public        String CLIENTID       = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
            ? Build.getSerial() : Build.SERIAL;//客户端ID,一般以客户端唯一标识符表示,这里用设备序列号表示

    @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 startService(Context mContext) {
        mContext.startService(new Intent(mContext, MyMqttService.class));
    }

    /**
     * 发布 (模拟其他客户端发布消息)
     *
     * @param message 消息
     */
    public static void publish(String message) {
        String topic = PUBLISH_TOPIC;
        Integer qos = 2;
        Boolean retained = false;
        try {
            //参数分别为:主题、消息的字节数组、服务质量、是否在服务器保留断开连接后的最后一条消息
            mqttAndroidClient.publish(topic, message.getBytes(), qos.intValue(), retained.booleanValue());
        } catch (MqttException e) {
            e.printStackTrace();
        }
    }

    /**
     * 响应 (收到其他客户端的消息后,响应给对方告知消息已到达或者消息有问题等)
     *
     * @param message 消息
     */
    public void response(String message) {
        String topic = RESPONSE_TOPIC;
        Integer qos = 2;
        Boolean retained = false;
        try {
            //参数分别为:主题、消息的字节数组、服务质量、是否在服务器保留断开连接后的最后一条消息
            mqttAndroidClient.publish(topic, message.getBytes(), qos.intValue(), retained.booleanValue());
        } catch (MqttException e) {
            e.printStackTrace();
        }
    }

    /**
     * 初始化
     */
    private void init() {
        String serverURI = HOST; //服务器地址(协议+地址+端口号)
        mqttAndroidClient = new MqttAndroidClient(this, serverURI, CLIENTID);
        mqttAndroidClient.setCallback(mqttCallback); //设置监听订阅消息的回调
        mMqttConnectOptions = new MqttConnectOptions();
        mMqttConnectOptions.setCleanSession(true); //设置是否清除缓存
        mMqttConnectOptions.setConnectionTimeout(10); //设置超时时间,单位:秒
        mMqttConnectOptions.setKeepAliveInterval(20); //设置心跳包发送间隔,单位:秒
        mMqttConnectOptions.setUserName(USERNAME); //设置用户名
        mMqttConnectOptions.setPassword(PASSWORD.toCharArray()); //设置密码

        // last will message
        boolean doConnect = true;
        String message = "{\"terminal_uid\":\"" + CLIENTID + "\"}";
        String topic = PUBLISH_TOPIC;
        Integer qos = 2;
        Boolean retained = false;
        if ((!message.equals("")) || (!topic.equals(""))) {
            // 最后的遗嘱
            try {
                mMqttConnectOptions.setWill(topic, message.getBytes(), qos.intValue(), retained.booleanValue());
            } catch (Exception e) {
                Log.i(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.i(TAG, "连接成功 ");
            try {
                mqttAndroidClient.subscribe(PUBLISH_TOPIC, 2);//订阅主题,参数:主题、服务质量
            } catch (MqttException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onFailure(IMqttToken arg0, Throwable arg1) {
            arg1.printStackTrace();
            Log.i(TAG, "连接失败 ");
            doClientConnection();//连接失败,重连(可关闭服务器进行模拟)
        }
    };

    //订阅主题的回调
    private MqttCallback mqttCallback = new MqttCallback() {

        @Override
        public void messageArrived(String topic, MqttMessage message) throws Exception {
            Log.i(TAG, "收到消息: " + new String(message.getPayload()));
            //收到消息,这里弹出Toast表示。如果需要更新UI,可以使用广播或者EventBus进行发送
            Toast.makeText(getApplicationContext(), "messageArrived: " + new String(message.getPayload()), Toast.LENGTH_LONG).show();
            //收到其他客户端的消息后,响应给对方告知消息已到达或者消息有问题等
            response("message arrived");
        }

        @Override
        public void deliveryComplete(IMqttDeliveryToken arg0) {

        }

        @Override
        public void connectionLost(Throwable arg0) {
            Log.i(TAG, "连接断开 ");
            doClientConnection();//连接断开,重连
        }
    };

    @Override
    public void onDestroy() {
        try {
            mqttAndroidClient.disconnect(); //断开连接
        } catch (MqttException e) {
            e.printStackTrace();
        }
        super.onDestroy();
    }
}

该 MyMqttService 类的大概逻辑就是开启服务后,调用init()方法初始化各个参数,包括服务器地址、用户名、密码等等,然后调用doClientConnection()方法连接MQTT服务器,iMqttActionListener用来监听MQTT是否连接成功,连接成功则订阅主题。mqttCallback为订阅主题的回调,收到消息后会执行该回调中的messageArrived()方法,拿到消息后进行UI更新,并调用response()方法响应给对方告知消息已到达或者消息有问题等。

2.3 开启服务

在MainActivity中开启服务,这里为了方便不做UI更新,所以就一行开启服务的代码,如下:

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;

public class MainActivity extends AppCompatActivity {

   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_main);
       MyMqttService.startService(this); //开启服务
   }
}

 

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/u010277958/article/details/102894910

智能推荐

AI嘻哈写歌词软件总结-程序员宅基地

文章浏览阅读1k次。(一)软件功能实现两个功能:根据主题生成歌词和辅助写歌词根据用户给定的主题生成一段歌词,歌词表达要流畅,语句通顺,押韵提供相关的词语和句子供用户选择,使用户在帮助下完成歌词创作核心模型主题生成首句模型-相似度计算 + 基于SIF加权的word2vec模型首句生成整段歌词模型-基本的Seq2Seq模型和双向Decoder + beam search的改进模型(二) 核心..._ai写rap歌词

基于STM32单片机多功能万年历控制系统设计_stm32万年历按键切换-程序员宅基地

文章浏览阅读334次。毕业设计 32单片机 万年历 温湿度采集 课程设计_stm32万年历按键切换

从本地或者网络读取图片,并转换为Bitmap图片_java 读取网页图像到bitmap-程序员宅基地

文章浏览阅读6.6k次。在做android项目时,我们经常需要从本地或者网络读取图片,并转换为Bitmap图片,以便使用,下面是读取本地图片并转换的方法:Java代码 /** * 得到本地或者网络上的bitmap url - 网络或者本地图片的绝对路径,比如: * * A.网络路径: url="http://blog.foreverlov_java 读取网页图像到bitmap

计算机组成原理|多功能ALU设计实验_设计一个具有8种运算功能的32位alu实验总结-程序员宅基地

文章浏览阅读9.8k次,点赞7次,收藏118次。多功能ALU设计实验一、实验目的与要求实验目的:(1)学习多功能ALU的工作原理,掌握运算器的设计方法(2)掌握运用Verilog HDL 进行行为描述与建模的技巧和方法实验要求:本实验要求设计一个具有8种运算功能的32位ALU,并能够产生运算结果的标志:结果为零标志ZF(Zero Flag)、溢出标志OF(Overflow Flag)。ALU通过3根控制线ALU_OP[2:0]..._设计一个具有8种运算功能的32位alu实验总结

iOS开发进阶之列表加载图片-程序员宅基地

文章浏览阅读484次,点赞10次,收藏5次。列表加载图片通常使用UITableView或UICollectionView,由于列表中内容数量不确定并且对于图片质量要求也不确定,所以对于图片加载的优化是很有必要的。

随便推点

Snipaste的使用_snipaste使用-程序员宅基地

文章浏览阅读7.3k次,点赞5次,收藏11次。Snipaste的使用_snipaste使用

使用python下载加密的流媒体m3u8视频文件,获取电影资源-程序员宅基地

文章浏览阅读273次,点赞3次,收藏8次。Python崛起并且风靡,因为优点多、应用领域广、被大牛们认可。学习 Python 门槛很低,但它的晋级路线很多,通过它你能进入机器学习、数据挖掘、大数据,CS等更加高级的领域。Python可以做网络应用,可以做科学计算,数据分析,可以做网络爬虫,可以做机器学习、自然语言处理、可以写游戏、可以做桌面应用…Python可以做的很多,你需要学好基础,再选择明确的方向。这里给大家分享一份全套的 Python 学习资料,给那些想学习 Python 的小伙伴们一点帮助!

在Qt中使用CreateProcess打开命令行并执行命令_qt.createqprocess()-程序员宅基地

文章浏览阅读351次。在Qt应用程序中,执行命令行命令并获取输出结果可以使用QProcess类。现在,我们可以在Qt应用程序中调用这个函数来执行命令行命令并获取输出结果。现在,我们可以在Qt应用程序中调用这个函数来执行命令行命令并获取输出结果。在上面的示例中,我们将命令设置为"dir",这将列出当前目录的内容。在上面的示例中,我们将命令设置为"dir",这将列出当前目录的内容。这样,当我们点击按钮时,程序将执行命令并将输出结果显示在文本编辑器中。这样,当我们点击按钮时,程序将执行命令并将输出结果显示在文本编辑器中。_qt.createqprocess()

java logutil_Java日志组件1---Jdk自带Logger(java.util.logging.Logger)-程序员宅基地

文章浏览阅读216次。最近在看日志的一些东西,发现利用JDK自带的log也可以简单的实现日志的输出,将日志写入文件的过程记录如下:1、新建LogUtil.Java(里面写了几个静态方法,为log设置等级、添加log控制台handler、添加log文件输出handler)packagecn.darkranger.log.logger;importjava.io.IOException;importjava.text.S..._logutil.java

此时不应有 \scala\bin\..\lib\jline-2.14.5.jar_c:\users\dell>scala 此时不应有 \scala\bin\..\lib\jline--程序员宅基地

文章浏览阅读221次。scala安装时,此时不应有 \scala\bin…\lib\jline-2.14.5.jar那是因为安装Scala时,默认安装到Program Files (x86)或者Program Files下,但是这俩个文件夹命名存在空格,这是从新安装,选择没有空格存在的文件夹下面即可。谢谢..._c:\users\dell>scala 此时不应有 \scala\bin\..\lib\jline-2.14.5.jar

本地搭建docker仓库的详细步骤_本地安装docker-程序员宅基地

文章浏览阅读1.7k次。在本地创建一个用于存储Docker镜像的目录,比如 /data/docker-registry。如果需要加速拉取公共镜像,可以配置阿里云或DaoCloud等国内提供的Docker镜像加速器。如果需要在其他机器上访问该私有仓库,则需要配置证书。使用docker tag将本地构建好的镜像打标签,并推送到私有仓库中。在官网下载Docker安装包进行安装,具体操作方式可以参考官方文档。至此,本地Docker仓库搭建完成。配置客户端访问证书(可选)拉取Registry镜像。启动Registry容器。_本地安装docker

推荐文章

热门文章

相关标签