通过 WebSphere MQ 遥测传输 (MQTT) 将 Android 手机引入物联网

本文通过几个示例程序,介绍了如何在 Eclipse 上开发基于 Android 平台的 MQTT 客户端程序,实现了 Android 平台的设备与 MQ 服务器间的消息互通,将 Android 开发和 WebSphere MQ 遥测传输 (MQTT) 开发两个新技术结合到了一起。MQTT 针对于物联网应提供了一套成熟的规范以及开发 API,可将各种移动设备连接至因特网和企业,从而降低了为智能设备构建应用程序的成本。将 MQTT 部署到 Android 平台,即可非常方便地将现今流行的手机、平板电脑等 Andorid 移动设备统一地连接起来,从而为物联网应用构建连通的平台。

王 博, 高级软件工程师, IBM

王博,现就职于 IBM CDL,从事于 WebSphere MQ 以及 JCA Adapters 的开发和测试工作。对于 MQ、SOA 以及物联网有一定的研究。可以通过 wangbowb@cn.ibm.com 联系作者。



2011 年 9 月 22 日

MQTT 简介以及适用场景用

IBM® WebSphere® MQ Telemetry Transport(简称 MQTT)是一种基于 TCP/IP 的轻量级发布 / 预订协议,用于连接大量的远程传感器和控制设备。在必须允许低带宽和不可靠的通信并且占用较少内存的设备上,专业化的应用程序就使用 MQTT 协议。用户可以编写自己的客户机以使用已发布的协议。

MQTT 产品作为 WebSphere MQ 产品的扩展,使用了 MQTT V3.1 版本的协议。它提供了一些小型客户机库,可以将这些客户机库嵌入到运行于不同设备平台上的智能设备中。使用客户机构建的应用程序使用 MQ Telemetry Transport(MQTT) 和 WebSphere MQ Telemetry 服务并借助 WebSphere MQ 来可靠地发布和预订消息。一个高级 MQTT 客户机(即设备的 WebSphere MQ Telemetry 守护程序)可以运行于多种平台上。它可以充当一个网络集中器,能够将更多的 MQTT 客户机连接至单个队列管理器。对于在网络发生短暂中断期间无法缓存消息的小型设备,它还可以为这些小型设备提供存储转发功能。

物联网,即 Internet-of-Things, 简称 IOT。它和能源、电子信息、医疗、交通、零售、物流、工业制造等行业息息相关。要实现物联网,首先需要将具备信息感知和通信能力的设备嵌入到我们关心的物品中,使其能连接到因特网或企业网络之上,实现互联互通。之后,互通的物品不仅要通过设备采集信息、实现智能的感知,更要结合一切先进的信息处理、数据挖掘等手段,与业务应用相结合,从后台到前端设备,实现智能的控制。

MQTT 结合物联网应用,它可以将各种移动设备连接至因特网和企业,降低了为智能设备构建应用程序的成本,从而为物联网应用构建连通的平台。


Android 开发方法简介

Android 是一个基于 Linux 平台的开源手机操作系统,它包括操作系统、用户界面中间件和一些重要的应用程序。Android SDK 为在 Android 平台上使用 Java 语言开发应用程序提供了工具和 API。

本文将介绍如何在 Eclipse 中开发 Android 应用程序,为此我们需要安装 Android SDK 以及在 Eclipse 中开发 Android 项目的插件 ADT。

本文使用 Android SDK 2.2 版本进行开发。


场景开发

MQTT 的安装

WebSphere MQ Telemetry 运行时是 WebSphere MQ 队列管理器的扩展。在 Windows 平台上安装 MQ 以及 MQTT,首先需要确保您的用户必须是 Administrators 组的成员。在 Linux 系统上安装的话需要确保您的用户必须具有 root 权限。本文将以 Windows 平台为例进行介绍。

首先参考 WebSphere MQ 产品的 InfoCenter,安装 MQ 运行时以及 MQ Explorer。之后安装 MQTT,MQTT 作为 MQ 的扩展,可以在 MQ 安装好后进行扩展安装。

安装好 MQTT 后,通过开始菜单启动 WebSphere MQ 资源管理器,也可以使用 strmqcfg 命令来启动。

在 WebSphere MQ 资源管理器的 Navigator 选项卡中,单击 Queue Managers > Queue Manager 名称 > Advanced > Telemetry,打开 Welcome to MQ Telemetry 面板,单击 Define sample configuration。

图 1. “Welcome to MQ Telemetry”面板
图 1. “Welcome to MQ Telemetry”面板

Define a sample configuration 窗口打开,它展示了将要对队列管理器进行的配置,我们可以浏览这些信息以查看具体需要哪些配置。查看后点击 Finish,MQTT 将会被自动配置。

图 2. “Define a sample configuration”面板
图 2. “Define a sample configuration”面板

配置完成后,MQTT Client Utility 将被弹出,我们可以用这个工具进行测试,这个工具模拟了 MQTT 的客户端,可以用其测试连接刚刚配置好的 MQTT 服务器,以及尝试发布一些消息。

图 3. “MQTT Client Utility”测试工具
图 3. “MQTT Client Utility”测试工具

MQTT 服务器端的配置

运行 MQ 安装目录 \mqxr\samples 目录下的 SampleMQM.bat 批处理文件即可完成对 MQTT 服务器端的配置,其中包括创建队列管理器、创建本地队列、开启监听服务等。

清单 1. SampleMQM.bat 文件内容
 crtmqm QM1 
 strmqm QM1 

 echo DEFINE QLOCAL('SYSTEM.MQTT.TRANSMIT.QUEUE') USAGE(XMITQ) MAXDEPTH(100000)
  | runmqsc QM1 
 echo ALTER QMGR DEFXMITQ('SYSTEM.MQTT.TRANSMIT.QUEUE') | runmqsc QM1 

 // Allow guest to send messages to clients attached to the MQTT Listener. 
 setmqaut -m QM1 -t q -n SYSTEM.MQTT.TRANSMIT.QUEUE -p guest -all +put 

 // Allow guest to publish and subscribe on any topic. 
 setmqaut -m QM1 -t topic -n SYSTEM.BASE.TOPIC -p guest -all +pub +sub 

 // Install the service into the QMgr 
 type "%SAMPLESDIR%\installMQXRService_win.mqsc" | runmqsc QM1 

 // Start the service 
 echo START SERVICE(SYSTEM.MQXR.SERVICE) | runmqsc QM1 

"%SAMPLESDIR%\..\bin\controlMQXRChannel.bat" -qmgr=QM1 
-mode=newchannel -chlname=PlainText -port=1883 -mcauser=guest

其中,crtmqm 和 strmqm 命令创建并开启了名为 QM1 的队列管理器。使用命令 runmqsc 可以进入 MQ 的脚本命令控制台 MQSC,在其中可以进行一些对 MQ 的配置,比如我们用 DEFINE QLOCAL 命令新建了一个传输队列用来进行消息的传输,并通过 ALTER QMGR 命令将其设置为缺省的传输队列。在这里,传输队列负责暂存 MQTT 服务器端与 MQTT 客户端(下面要介绍的 Android 手机)之间即将进行通信的消息。

之后,使用了两条 setmqaut 语句为 MQTT 通信添加了一些必要的权限。然后通过 type installMQXRService_win.mqsc 以及 START SERVICE 两条语句向队列管理器 QM1 中安装并启动了 MQTT 服务。这样,我们当前的队列管理器 QM1 就可以支持 MQTT 扩展了。

最后一条语句调用了 controlMQXRChannel.bat 批处理文件创建并开启了一个连接通道,这样客户端就可以通过 1883 端口连接到我们刚刚配置好的 MQTT 服务器了。

至此,MQTT 服务器端的配置已经完成。但我们为了使其可以接收到某一个特定主题的消息,我们还必须加入对这个主题的定义。在控制台通过 runmqsc 命令进入 MQSC,在这里我们可以定义 MQ 的对象,如本地队列、主题等。

清单 2. 添加 MQTTExamples 主题
 DEFINE TOPIC('MQTTExamplesTopic') TOPICSTR('MQTT Example') REPLACE
 DEFINE QLOCAL('MQTTExampleQueue') REPLACE
 DEFINE SUB('MQTTExampleSub') DEST('MQTTExampleQueue') TOPICOBJ('MQTTExampleTopic')
  REPLACE

在这里我们定义了一个名为 MQTTExamplesTopic 的主题,它将接受所有主题字符串为“MQTT Example”字样的消息,并可以通过名为 MQTTExampleSub 的订阅(MQTT 中的一种订阅关系),将这些消息存储到名为 MQTTExampleQueue 的本地队列中。

Android 开发环境配置

本章将介绍如何使用 Android SDK 2.2 进行开发。

首先,需要下载并安装 Java 的 JDK,本文的示例使用了 JDK 6 update 24 版本的 JDK。

之后,下载并安装新版本的 Eclipse 开发工具,本文的示例使用了 Helios Service Release 2 版本的 Eclipse( 即 Eclipse 3.6.2)。

然后下载并安装 Android 的 SDK,新版本的 Android SDK 需要由 Google 官方提供的 Android SDK Tools 进行统一的安装管理。从以下网址下载 Windows 平台的 Android SDK Tools 并安装:http://developer.android.com/sdk/

安装好后运行 Android SDK Tools 安装目录下的 SDK Manager.exe。

图 4. Android SDK Tools 的安装目录
图 4. Android SDK Tools 的安装目录

SDK Manager 启动后,在其 Available Packages 选项卡中选择组件进行安装。

图 5. 选择组件进行安装
图 5. 选择组件进行安装

安装好的组件会被显示在 Installed packages 选项卡中。本文将使用 Android SDK 2.2 进行开发,因此请确保 2.2 版本的 SDK 安装妥当,2.2 版本的 SDK 对应的 API 版本是 API 8。

之后,我们还需要为 Eclipse 安装开发 Android 项目的插件 ADT。在 Eclipse 中选择 Help->Install New Software,在弹出窗口中点 Add 按钮添加 ADT 的安装网址:https://dl-ssl.google.com/android/eclipse/

图 6. 安装 ADT
图 6. 安装 ADT

选择所有包,点 Next,安装向导会自动下载并安装这些组件。

Eclipse 重启后,选择 Windows->Preferences->Android,在 SDK Location 中选择 Android SDK 的路径,点 Apply。

图 7. 选择 Android SDK 路径
图 7. 选择 Android SDK 路径

在这里,我们可以通过查看 Build、DDMS、Editors 等子选项浏览 Android SDK 的属性。对于本文的示例,保留默认值即可。

最后,我们需要添加一个模拟器设备以便于调试。在 Eclipse 中选择 Windows->Android SDK and AVD Manager,在 Virtual devices 中通过 New 按钮添加一个 Android 2.2 设备,在这里我们还可以选择设备的屏幕尺寸、内存大小等参数。

图 8. 添加一个模拟器设备
图 8. 添加一个模拟器设备

场景开发:Android 客户端向 MQ 服务器发送消息

在 Eclipse 中新建一个 Android Project,如下图所示填写项目名称、默认的 Activity 名称和 package 名等信息。另外请注意,在这里选择使用版本为 2.2 的 Android SDK。

图 9. 新建 Android Project
图 9. 新建 Android Project

点 Finish 键完成新项目的创建,Eclipse 帮我们生成了如下结构的项目。

图 10. Android Project 的项目结构
图 10. Android Project 的项目结构

我们来介绍一下生成的文件:

  • HelloWorld.java – Android 项目的默认 Activity 类,继承自 android.app.Activity,整个程序的起点就是这个类里面的 onCreate() 方法。
  • R.java – Android 系统需要的资源文件,在 Eclipse 中会自动生成及更新,无需手动修改。里面存储了图片、布局、界面元素、字符串等资源的索引。
  • 三个 drawable 文件夹及 icon.png 文件 – Android 应用程序的图标,针对目标设备的不同分辨率,最终将会有一个被采用。
  • layout 文件夹及 main.xml 文件 – Android 程序的界面布局。
  • values 文件夹及 strings.xml – 用来存储文本信息的资源文件。
  • AndroidManifest.xml – 记录和 Android 程序相关的配置信息,是一个非常重要的文件,比如我们后面将要介绍的授予应用程序访问网络的权限,就是在这个文件中修改的。

项目生成后,我们首先需要添加 MQTT 的客户端 API 包。在 MQ 安装目录 \mqxr\lib 目录下找到名为 com.ibm.micro.client.mqttv3.jar 的 jar 包,将其复制到 Android 项目下的 assets 目录中,并在项目属性中的 Java Build Path->Libraries 中通过 Add Jar 添加这个 jar 包,这样我们就可以在这个 Android 项目中使用 MQTT 的客户端 API 了。

现在,我们就可以进行 MQTT 客户端程序的编写了。MQTT 的 InfoCenter 上有一些简单的示例程序可以参考,在此我们将程序简化以便于理解。新建一个名为 PubSync 的类。

清单 3. PubSync.java 的内容
 package com.ibm.websphere.cdl; 
 import com.ibm.micro.client.mqttv3.*; 

 public class PubSync { 
 public String doTest(){ 
 try { 
 MqttClient client = new MqttClient("tcp://9.119.154.32:1883","java_client", null); 
 MqttTopic topic = client.getTopic("MQTT Example"); 
 MqttMessage message = new MqttMessage("Hello World. Hello IBM".getBytes()); 
 message.setQos(1); 
 client.connect(); 
 MqttDeliveryToken token = topic.publish(message); 
 while (!token.isComplete()){ 
 token.waitForCompletion(1000); 
 } 
 client.disconnect(); 
 } catch (Exception e) { 
 e.printStackTrace(); 
 return "failed"; 
 } 
 return "success"; 
 } 
 }

在上面的程序代码中,我们首先创建了一个 MqttClient 对象 client 用于连接到远程的 MQTT 服务器,在这里我们的 MQTT 服务器位于 IP 为 9.119.154.32 的机器上,正如我们之前配置的那样,MQTT 服务器的监听端口为 1883。"java_client"用来标识客户端名称。

之后我们创建了一个名为"MQTT Example"的主题,对象名为 topic。还记得我们在 MQTT 服务器端的配置章节中定义的 MQTTExampleTopic 吗?它的主题字符串同样为"MQTT Example",这样可以保证我们现在创建的主题消息可以被服务器正确地订阅并接收。并且根据服务器端的配置,将接收到的消息存储在对应的本地队列中(MQTTExampleQueue)。

接下来我们又创建了一条消息,并将消息的服务质量级别 (QoS) 设置为 1。消息内容为我们将向服务器发送的一条文本信息。服务质量 (QoS) 确定消息在 MQTT 客户机与队列管理器之间传递时的可靠程度,MQTT 客户机提供了三种服务质量:至多一次(QoS=0)、至少一次 (QoS=1,默认值)和刚好一次 (QoS=2)。三种 QoS 的区别请参考 MQTT 的 InfoCenter,在此我们使用默认的 1,以避免出现网络权限或文件读写权限不足等问题引发的异常。

然后我们调用了 client 对象的 connect() 方法进行真正的网络连接,并调用 topic 对象的 publish() 方法将我们定义好文本内容的消息发送给订阅者,也就是服务器端。通过查询 publish() 方法返回的 MqttDeliveryToken 类型的对象 token,我们即可得知操作是否顺利完成。

最后,当得知操作完成后,不要忘记关闭网络连接释放资源:client.disconnect()。至此,MQTT 的客户端程序就完成了,我们注意到上述程序并没有用到 Android 的 API,所以这段程序理论上可以在任何 Java 客户端执行,为了调试的方便我们可以在开发这段代码的机器上使其调试通过。

现在,我们使用一种最简单的办法使这段程序能被 Android 应用调用到。在 HelloWorld.java 的 onCreate() 方法的最后,加入以下几行代码:

清单 4. onCreate() 方法中添加的代码
 String strResult = PubSync.doTest();
   TextView tv = new TextView(this);
   tv.setText(strResult);
   setContentView(tv);

我们在这里直接调用了用于向 MQTT 服务器发布消息的 doTest() 方法,并将返回结果显示在一个界面控件文本框中。

Android 应用程序打包部署及测试

由于本程序需要联网才可以运行,因此我们需要授予该程序网络访问的权限。在 Android 程序中修改 AndroidManifest.xml 文件来进行权限的修改。在 Eclipse 中打开该文件,在 Permissions 选项卡中列出了该程序的所有权限,Android 程序默认没有任何权限。通过 Add 按钮我们添加下图中的几种权限,以使应用程序可以访问网络。

图 11. 添加权限
图 11. 添加权限

这些权限的修改都会被写入到 AndroidManifest.xml 文件中,随程序一起部署到 Android 设备里。Android 程序对于权限的要求十分严谨,如网络操作、文件操作、对手机硬件的操作等都需要特殊的权限,因此在开发 Android 程序的时候一定要注意手否授予了适当的权限,否则调试起来会很麻烦。

设置完权限后,我们可以调用之前配置好的模拟器设备进行调试。选中 Activity 类,即 HelloWorld.java,点运行,选择运行为 Android Application。等待一段时间后,模拟器设备将会被启动,Eclipse 会将我们的项目打包部署在这个模拟器设备中并运行它。此过程可能等待的时间较长。

图 12. 模拟器中的运行结果
图 12. 模拟器中的运行结果

从运行结果中我们看到,有一条文本信息显示操作成功,这就是我们添加的唯一界面控件—— TextView。

调试完成后,我们就可以将程序打包部署了。在 Eclipse 中右键单击项目,点 Export。在这里我们看到已经可以将项目导出为 Android 的应用程序了。

图 13. 导出项目
图 13. 导出项目

选择好项目之后,在 Keystore selection 窗口选择 keystore 文件或生成新的 keystore 文件,并输入密码。这里的 keystore 是作为将来把应用程序发布到 Google Android 市场时的唯一标识的。

图 14. 选择 keystore
图 14. 选择 keystore

在最后的窗口选择一个目标 APK 文件生成。将这个 APK 文件复制到 Android 手机,运行它即可安装。请注意由于我们开发的是基于 Android SDK 2.2 的应用程序,因此请确保手机支持 Android 2.2 版本。

首先将手机连入局域网,我们采用 wifi 连接的方式,将手机连入和 MQTT 位于同一局域网的路由器。由于我们的程序没有做任何错误处理,因此请务必确保手机和 MQTT 服务器之间的网络畅通。然后在手机上运行这个程序,我们得到了同模拟器一致的结果。

图 15. 运行结果
图 15. 运行结果

同时,在 MQTT 服务器端看到收到了一条消息。Current queue depth 为 1,说明 MQTTExampleQueue 中有一条未读消息。

图 16. MQ Explorer
图 16. MQ Explorer

使用工具 RFHUtil 可以查看收到的消息的内容。

图 17. RFHUtil 查看消息内容
图 17. RFHUtil 查看消息内容

除了 RFHUtil 工具以外,也可以使用 MQ 自带的查看队列内容的工具 amqsget 查看队列内容,amqsget 为 C 语言编写,随 MQ 一起部署,直接在命令行模式下就可以运行。运行结果如下。

清单 5. amqsget 运行结果
 C:\>amqsget MQTTExampleQueue QM1 
 Sample AMQSGET0 start 
 MQGET ended with reason code 2110 
 message <Hello World. Hello IBM> 
 no more messages 
 Sample AMQSGET0 end

另外,一旦某条消息被 RFHUtil 或 amqsget 读走,它将从队列中被删除,同时队列的 current queue depth 将减 1。

场景开发:Android 监听并接收外界发来的消息

我们刚刚完成了 Android 手机设备向 MQTT 服务器发送消息的程序,现在我们来实现 Android 手机设备监听某一特定主题,并获取这个主题的消息的程序。

首先我们实现了一个名为 Subscribe 的类。

清单 6. Subscribe.java 的内容
 package com.ibm.websphere.cdl; 
 import android.os.Handler; 
 import com.ibm.micro.client.mqttv3.MqttClient; 
 import com.ibm.micro.client.mqttv3.MqttConnectOptions; 

 public class Subscribe { 
 public static String doTest(Handler handler) { 
 try { 
 MqttClient client = new MqttClient("tcp://9.119.154.32:1883", "java_client", null); 
 CallBack callback = new CallBack("java_client", handler); 
 client.setCallback(callback); 
 MqttConnectOptions conOptions = new MqttConnectOptions(); 
 conOptions.setCleanSession(false); 
 client.connect(conOptions); 
 client.subscribe("MQTT Example", 1); 
 Thread.sleep(10000); 
 client.disconnect(); 
 } catch (Exception e) { 
 e.printStackTrace(); 
 return "failed"; 
 } 
 return "success"; 
 } 
 }

和 PubSync 一样,我们创建了一个 MqttClient 对象 client 用于连接到远程的 MQTT 服务器。然后我们构造了一个 CallBack 对象用来接收消息。在构建这个 CallBack 对象的时候我们传入了一个 Handler 对象用于更新主界面 UI ——将消息内容显示在主界面上。这个 Handler 对象是由 Activity 类(即 Helloworld 类)生成的,由于 Android 程序不可以在子线程更新 Activity 线程创建的界面控件,因此我们采用 Handler 的机制,由子线程(即 Callback 线程)向 Activity 线程发送 UI 更新的消息,并最后由 Activity 完成 UI 更新。

之后我们通过调用 client 对象的 subscribe() 方法使其订阅主题字符串为"QTT Example"的消息。为了便于演示,本示例程序将等待 10 秒钟 (10000 毫秒 ),我们将在这段时间内在 MQTT 服务器端发送若干条消息。在这 10 秒内,CallBack 线程会持续监听主题字符串为"MQTT Example"的消息,如果有这样的消息,它将通知主线程(Activity 类 HellowWorld 所运行的线程)在界面显示这些消息。您也可以修改您的程序以使这个时间更长。

现在让我们来看看 Callback 类的内容。

清单 7. Callback.java 的内容
 package com.ibm.websphere.cdl; 
 import android.os.*; 
 import com.ibm.micro.client.mqttv3.*; 

 public class CallBack implements MqttCallback { 
 private String instanceData = ""; 
 private Handler handler; 

 public CallBack(String instance, Handler handler) { 
 instanceData = instance; 
 this.handler = handler; 
 } 

 public void messageArrived(MqttTopic topic, MqttMessage message) { 
 try { 
 Message msg = Message.obtain(); 
 Bundle bundle = new Bundle(); 
 bundle.putString("content", message.toString()); 
 msg.setData(bundle); 
 handler.sendMessage(msg); 
 } catch (Exception e) { 
 e.printStackTrace(); 
 } 
 } 
 public void connectionLost(Throwable cause) {} 
 public void deliveryComplete(MqttDeliveryToken token) {} 
 }

Callback 类继承自 MqttCallback,需要实现 messageArrived()、connectionLost() 和 deliveryComplete() 三个方法以响应不同的事件。messageArrived() 方法负责响应收到消息后的事件,在本示例中我们只用到了这个方法。我们将消息的内容放到一个 Bundle 对象中并由它构建了一个 Message 对象,最后把这个包含了消息内容的 Message 对象通过 Handler 发送给主线程 HellowWorld,委托其将消息内容更新到主界面 UI。

最后我们再来看一下修改后的主线程 HellowWorld 类。

清单 8. 的内容
 package com.ibm.websphere.cdl; 
 import android.app.Activity; 
 import android.widget.TextView; 
 import android.os.*; 

 public class HelloWorld extends Activity { 
 private TextView tv; 

 /** Called when the activity is first created. */ 
    @Override 
    public void onCreate(Bundle savedInstanceState) { 
        super.onCreate(savedInstanceState); 
        setContentView(R.layout.main); 
        
        tv = new TextView(this); 
        String strResult = Subscribe.doTest(mHandler); 
    } 
    
 private Handler mHandler = new Handler(){ 
 @Override 
 public void handleMessage(Message msg) { 
 super.handleMessage(msg); 
 String strContent = tv.getText().toString(); 
 strContent += "\n" + msg.getData().getString("content"); 
 tv.setText(strContent); 
 setContentView(tv); 
 } 
 }; 
 }

在这里我们新建了一个内部类对象 mHandler,它的 handleMessage() 方法接收 Callback 类通过 mHandler 对象发来的消息。根据前文的介绍可知,mHandler 对象包含了 MQ 消息的内容。handleMessage() 方法将这些 MQ 消息的内容更新在 UI 控件 TextView 中,这样用户就可以在程序的界面看到 MQTT 服务器端发送过来的消息内容了。

按照前文的介绍,在模拟器中安装并运行程序。我们可以事先在 MQTT 服务器端发送出几条主题字符串为"MQTT Example"的消息,或者在程序运行中等待的 10 秒内发出这样的消息。在 MQ Explorer 中选中 MQTTExampleTopic,点右键选中 Test Publication。

图 18. Test Publication
图 18. Test Publication

输入测试消息并点 Publish message 发送。在这里我们可以发送多条消息。

图 19. 发送测试消息
图 19. 发送测试消息

019.jpg

程序的运行结果如下,收到了三条消息,并显示出消息内容。

图 20. 运行结果显示收到的消息
图 20. 运行结果显示收到的消息

程序改进及未尽事宜

Android 开发的一大优势是 SDK 中已经预先定义了非常多的界面 UI 控件,我们可以非常方便地为程序添加 UI 效果。比如我们为 PubSync 程序添加一个界面,使其可以接收来自于用户输入的参数,从而避免了将 MQTT 服务器的连接信息及消息内容写死在程序里面。

打开 layout 目录下的 main.xml 文件,Eclipse 会默认将其打开为界面元素,通过拖拽左边的控件,我们可以快速地构建一个界面。

图 21. 为 Android 程序添加界面
图 21. 为 Android 程序添加界面

我们在界面上加入了一些文本框供用户输入数据,并且添加了一个按钮。一旦点击这个按钮,程序将执行一个定义好的方法进行后续的操作。为此,我们需要在 onCreate() 方法中为这个按钮添加一个单击事件的响应函数。

清单 9. 修改后的 onCreate() 方法
 public void onCreate(Bundle savedInstanceState) { 
 super.onCreate(savedInstanceState); 
 setContentView(R.layout.main); 
 Button btnSend = (Button) findViewById(R.id.btnSend); 
 btnSend.setOnClickListener(listener_Button_Start); 
 }

之后我们要实现这个响应函数。首先通过 readConfiguration() 方法读入界面参数,这个方法是我们自己实现的内部方法,通过界面控件的 id 定位到控件对象并读取用户输入的数据。然后调用 PubSync 的 doTest() 方法执行发送消息的操作,在这里我们已经对 doTest() 方法进行了改造,它不再通过写死的参数连接 MQTT 服务器,而是通过 readConfiguration() 方法从界面获得这些信息。最后将执行结果显示在名为 txtResult 的 TextView 界面控件中。

清单 10. Send 按钮的单击事件响应函数
 private OnClickListener listener_Button_Start = new OnClickListener() { 
 @Override 
 public void onClick(View v) { 
 MyProperties myProperties = readConfiguration(); 
 String result = PubSync.doTest(myProperties); 
 TextView tvResult = (TextView) findViewById(R.id.txtResult); 
 tvResult.setText(result); 
 } 
 };

这样,我们的程序就变得比较美观了,用户在执行该程序的时候可以选择连接到某一台 MQTT 服务器,而且可以自定义消息的内容。

当然,该程序还是相当不完善的,我们还没有为其加入任何容错处理、网络控制、移动设备的电源控制等功能。尤其是没有网络控制功能,使程序的适用性很小,如果在执行改程序前手机并没有通过 wifi 网络连接到 MQTT 服务器所在的网络,则程序将出错。一个比较好的解决方案是程序在被执行时自动判断设备的网络状态,如果没有网络连接,则程序自动尝试连接到网络。读者如果有兴趣,可以自行参考 Android 的开发文档设计这些内容使程序更加健壮。

参考资料

学习

获得产品和技术

讨论

条评论

developerWorks: 登录

标有星(*)号的字段是必填字段。


需要一个 IBM ID?
忘记 IBM ID?


忘记密码?
更改您的密码

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件

 


在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。

所有提交的信息确保安全。

选择您的昵称



当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

标有星(*)号的字段是必填字段。

(昵称长度在 3 至 31 个字符之间)

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

 


所有提交的信息确保安全。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=WebSphere
ArticleID=760918
ArticleTitle=通过 WebSphere MQ 遥测传输 (MQTT) 将 Android 手机引入物联网
publish-date=09222011