简介

本文探究了 Android 的网络功能。了解如何利用 Android 的网络选项来实现有趣、有用的东西。Android 平台非常适合 Java™ 开发人员:他们可以使用已有的技能将网络连接带到一个移动或 “嵌入式” 平台中。

在本文中,了解用于 Android 应用程序的网络选项以及基本的 Android 联网技巧。本文研究一个真实的应用程序,它在结合使用环境监视系统时需要具备联网功能。这类系统为什么如此重要?原因之一是:如果您的朋友需要外出几个星期,在他离开后,他打电话给我,让我从他家里找到某样东西并邮寄给他。我来到他的家里,发现供暖设备已经被切断并且水管已经冻裂 — 场面非常混乱。如果备有一个温度监控系统,那么就可以避免出现这类事故。本文将探查 Android 在这类监控系统中扮演的角色。


Android 联网功能

Android 基于 Linux® 内核,包含一组优秀的联网功能。如果尚未安装 Android SDK,那么需要 下载 它才能实践本文的示例。

表 1 展示了 Android SDK 中一些与网络有关的包。


表 1. Android SDK 网络包
包 描述
java.net 提供与联网有关的类,包括流和数据包(datagram)sockets、Internet 协议和常见 HTTP 处理。该包是一个多功能网络资源。有经验的 Java 开发人员可以立即使用这个熟悉的包创建应用程序。
java.io 虽然没有提供显式的联网功能,但是仍然非常重要。该包中的类由其他 Java 包中提供的 socket 和连接使用。它们还用于与本地文件(在与网络进行交互时会经常出现)的交互。
java.nio 包含表示特定数据类型的缓冲区的类。适合用于两个基于 Java 语言的端点之间的通信。
org.apache.* 表示许多为 HTTP 通信提供精确控制和功能的包。可以将 Apache 视为流行的开源 Web 服务器。
android.net 除核心 java.net.* 类以外,包含额外的网络访问 socket。该包包括 URI 类,后者频繁用于 Android 应用程序开发,而不仅仅是传统的联网方面。
android.net.http 包含处理 SSL 证书的类。
android.net.wifi 包含在 Android 平台上管理有关 WiFi(802.11 无线 Ethernet)所有方面的类。并不是所有设备都配备了 WiFi 功能,特别是 Android 在 Motorola 和 LG 等手机制造商的 “翻盖手机” 领域获得了成功。
android.telephony.gsm 包含用于管理和发送 SMS(文本)消息的类。一段时间后,可能会引入额外的包来来为非 GSM 网络提供类似的功能,比如 CDMA 或 android.telephony.cdma 等网络。

上表并没有列出所有包,但是可以让您清楚地意识到该平台的强大功能。下一小节将介绍一些简单的网络示例。


简单的网络示例

为了演示将 Android 连接到一个网络有多么简单,这个示例将展示如何从 Web 页面发送文本。可以 下载 本例的源代码。图 1 展示了应用程序的实际使用。


图 1. 从 Web 页面获取文本
从 Web 页面获取文本

本节提供了构建示例应用程序所需的代码。我们将首先查看 UI 部分,然后介绍与网络有关的代码。

共有三个 UI 元素:

  • EditText 让用户能够进入一个 Web 页面(图 1 和 清单 2 所示的 http://developer.android.com)。
  • 使用一个按钮告诉程序取回 Web 页面文本。
  • 检索回数据后,它将显示在 TextView 中。

清单 1 展示了 main.xml 文件,这是该应用程序的完整 UI 布局。


清单 1. main.xml
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:orientation="vertical"    android:layout_width="fill_parent"    android:layout_height="fill_parent"    ><EditText android:layout_height="wrap_content"android:id="@+id/address"android:layout_width="fill_parent"android:text="http://google.com"></EditText><Button android:id="@+id/ButtonGo"  android:layout_width="wrap_content"  android:layout_height="wrap_content" android:text="go!" ></Button><TextView      android:layout_width="fill_parent"     android:layout_height="fill_parent"     android:background="#ffffff"    android:textColor="#000000"android:id="@+id/pagetext"    /></LinearLayout>

清单 2 展示了本示例使用的 Java 代码。


清单 2. GetWebPage.java
package com.msi.getwebpage;import android.app.Activity;import android.os.Bundle;// used for interacting with user interfaceimport android.widget.Button;import android.widget.TextView;import android.widget.EditText;import android.view.View;// used for passing data import android.os.Handler;import android.os.Message;// used for connectivityimport java.io.BufferedReader;import java.io.InputStreamReader;import java.net.URL;import java.net.URLConnection;public class GetWebPage extends Activity {    /** Called when the activity is first created. */    Handler h;@Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.main);                final EditText eText = (EditText) findViewById(R.id.address);        final TextView tView = (TextView) findViewById(R.id.pagetext);                this.h = new Handler() {            @Override            public void handleMessage(Message msg) {                // process incoming messages here                switch (msg.what) {                    case 0:                    tView.append((String) msg.obj);                    break;                }                super.handleMessage(msg);            }        };        final Button button = (Button) findViewById(R.id.ButtonGo);        button.setOnClickListener(new Button.OnClickListener() {            public void onClick(View v) {            try{            tView.setText("");                // Perform action on click                URL url = new URL(eText.getText().toString());                    URLConnection conn = url.openConnection();                    // Get the response                    BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));                    String line = "";                    while ((line = rd.readLine()) != null) {                Message lmsg;                        lmsg = new Message();                        lmsg.obj = line;                        lmsg.what = 0;                        GetWebPage.this.h.sendMessage(lmsg);                    }            }            catch (Exception e){            }            }        });            }}

这些代码可以分解成一些常见的部分。这里使用一些重要(必需)的导入语句来恰当地引用 UI、数据传递以及应用程序中使用的与网络有关的类。所有与网络相关的代码出现在 OnClickListenerOnClick 方法中。在选择 图 1 所示的标签为 go! 的按钮之后调用这些代码。

URLURLConnection 类共同提供与用户所选的 Web 站点的连接。BufferedReader 的一个实例负责从 Web 站点连接中读取传入的数据。每读取一行代码,文本就被附加到一个 TextView。数据并没有直接指定给 TextView(但是在本例中可以)。我们引入了一种设计模式,即创建一个消息对象并将该对象发送到一个处理程序的实例。这是更新 UI 的一种比较可取的方法,对可能需要同时运行多个线程的应用程序而言尤其如此。

在示例中,Android 应用程序与 HTTP Web 服务器进行通信,比如 Apache 或 Internet Information Server(IIS 位于 Microsoft® 服务器上)。如果应用程序直接与 TCP socket 对话,那么您将以不同的方式实现应用程序。清单 3 所示的代码片段展示了另一种与远程服务器交互的方式。这个清单被实现为一个单独的线程。


清单 3. Daytime 客户机
    public class Requester extends Thread {        Socket requestSocket;        String message;        StringBuilder returnStringBuffer = new StringBuilder();        Message lmsg;        int ch;        @Override        public void run() {            try {                this.requestSocket = new Socket("remote.servername.com", 13);                InputStreamReader isr = new InputStreamReader(this.requestSocket.getInputStream(), "ISO-8859-1");                while ((this.ch = isr.read()) != -1) {                    this.returnStringBuffer.append((char) this.ch);                }                this.message = this.returnStringBuffer.toString();                this.lmsg = new Message();                this.lmsg.obj = this.message;                this.lmsg.what = 0;                h.sendMessage(this.lmsg);                this.requestSocket.close();            } catch (Exception ee) {                Log.d("sample application", "failed to read data" + ee.getMessage());            }        }    }

与前面的示例类似,上面的代码使用消息和处理程序方法来将数据发送给调用者,调用者将更新 UI 并执行后续处理。与 清单 1 不同,这个例子并没有与 HTTP 服务器通信,因此没有使用 URLConnection 类。相反,使用了较低级的 Socket 类在端口 13 打开与远程服务器的基于流的 socket 连接。端口 13 是典型的 “Daytime Server” 应用程序。

Daytime Server 接受传入的 socket 连接并以文本的形式将日期和时间发送给调用 socket。一旦发送完数据,服务器将关闭 socket。示例也展示了 InputStreamReader 的使用和一个特定字符编码。

发送文本消息是您需要使用 Android 完成的另一项任务。清单 4 展示了一个示例。


清单 4. 发送一条文本消息
void sendMessage(String recipient,String myMessage) { SmsManager sm = SmsManager.getDefault(); sm.sendTextMessage("destination number",null,"hello there",null,null);}

发送文本消息非常简单。首先,使用静态方法 getDefault() 获取对 SmsManager 的引用。然后调用 sendTextMessage 方法。参数为:

接收者的手机号
包括区号。
服务中心电话号码
使用 null 值表示您同意使用默认服务中心来处理消息。除了非常特殊的应用程序外,几乎所有应用程序都对这个参数使用 null 值。
消息的实际内容
将消息长度保持在 160 字节以内,除非您可以接受将数据分为多个消息发送。
未收到消息 intent
如果消息被发送或出现了错误,那么将开始一个可选的 intent。如果不需要这类通知,那么可以为此参数传递一个 null 值。(参见 参考资料 了解有关 intent 和 Android 基本原理的更多信息)。
收到消息 intent
当收到发送确认后,将开始一个可选的 Intent。如果发送通知不重要的话,那么可以为这个参数传递一个 null 值。

不管是连接到 Web 页面还是连接到定制 TCP 应用程序,Android 平台都可以立即反应并且能够提供帮助。如 清单 4 所示,发送文本消息非常简单。通过使用可选的 intent 参数,甚至可以在消息被发送并交付后采取操作。这是其他移动平台所不具备的强大特性。

下一节将快速浏览一个真实的应用程序设计。


环境监控系统

在这个场景中,我们假设您是企业所在的若干办公场所的资产管理员。管理资产与管理数据中心没有太大的差别 — 一般情况下都很枯燥,只有出现紧急的情况下工作才会比较有意思。几天前,一台使用了 10 年的热水器突然漏水,渗到一个装满老式 PC 和培训手册的存储柜,您必须检查一下清理情况。幸运的是,您当时没有外出。如果您在旅途中的话,那么情形将非常糟糕。此类灾难性事故促使我们考虑使用 Android 来帮助监视资产的维护情况。图 2 展示了此类系统的一个高级方框图。


图 2. 监控系统的高级方框图
监控系统的高级方框图

此架构是一种比较传统的方法,使用一个微控制器与一些简单场景进行交互以收集数据。数据随后通过一个串行通信协议(比如 RS232 或 RS485)发送到控制器。控制器可以是一个 PC 或类似的机器。随后可以穿过防火墙通过 Internet 访问数据。Android 电话(比如 TMobile G1)之间使用的协议可以是 HTTP 或私有协定。

在控制器和配备 Android 的设备之间发送的数据将是表示以下内容的基本数据:

  • 出现漏水
  • 当前温度
  • 消耗的功率
  • 可能包含一些通用的类似数据和数字值

为什么需要关注消耗的功率?一个可能的原因就是有些人忘记关闭机器,因此电费单上的数字会一直增长。第二个理由有些复杂:假设您有一台非常大的冰箱,并且电源可能已被关闭。那么情况就复杂了,而且处理起来也需要很高的代价。或者,空调设备的断路器出现故障,因此机房无法保持恒定的温度。

基本的设计看上去是可行的。如果使用的是 Android,那么可以使用任何移动平台来替换 图 2 中的 Android。但如果使用配备了 Android 的设备替换微控制器,那应该怎么做呢?下一节将讨论对这个应用程序的扩展以及通过使用 Android 而启用的特性。


扩展应用程序

本文的第一个架构以一个微控制器为中心。微控制器可分为不同的外形和大小,从 Microchip 的 6 pin “10F” 到添加了外围设备、pin 和代码空间的 32 位大型微控制器。如果使用 Android 取代传统的微控制器放到设备中,会怎么样?对于某些应用程序而言,在成本方面是不可取的,但是根据图 3 的判断,这种方法也是可行的。


图 3. 在设备中使用 Android 的可能架构
在设备中使用 Android 的可能架构

使用嵌入式的方式部署 Android 为您提供了更加丰富的编程环境。您可以和以前一样继续监视湿度、温度和功率消耗特征,同时还可以观察到记录音频、视频和振动。您将拥有一个微报警、访问控制系统,以及一个环节监控工具。由于 Android 已经可以实现联网,您不需要使用控制器 PC 就可以实现监控并与网络直接对话。

这种方法还为现场更新软件提供了额外的好处。假设您希望为监控软件添加新的特性(或修复 bug)。如果使用传统的微控制器方法,那么任务执行起来将十分繁琐并且代价昂贵,甚至根本不可能实现。而对于 Android 而言,您可以获得更整洁的部署模型并拥有更好的灵活性。

Android 如今主要运行在移动手机中,但是它已经被移植到 NetBooks 和其他平台上。希望本文为您提供了一些好的思考内容。我现在该去运行我的系统了。您永远也不会知道下一次热水器漏水会在什么时候发生。


结束语

在本文中,我们大体介绍了 Android 的联网功能。您了解了一些自己可以创建的样例应用程序,包括与 Web 服务器交互和发送文本消息。您看到了如何将 Android 连接到一个真实的环境监控系统。通过代码示例,您了解到应该在什么时候将 Android 扩展到一些特殊应用程序中,比如嵌入式控制器。

请继续关注我的下一篇文章,它将介绍如何使用基于 Android 的电话构建一个婴儿监控系统。

更多相关文章

  1. Android消息机制不完全解析(上)
  2. Android系统对应用程序权限申请的处理方式分析
  3. Android中的sqlite简单示例
  4. Android应用程序汉化教程
  5. Android Content Provider详解及示例代码
  6. Google Android 应用程序结构
  7. android应用程序跳转到系统的各个设置页面
  8. android 学习示例
  9. 如何以编程方式退出android应用程序

随机推荐

  1. Android创建和删除桌面快捷方式
  2. android 小问题记录
  3. Mac Android(安卓)FFMpeg 编译及集成
  4. android 开机自启动程序2
  5. 【Android】Android内存溢出问题---用自
  6. android activity非全屏、透明
  7. Android studio 签名 报错:Could not down
  8. android 资源获取
  9. Android drawable 目录下 创建子目录问题
  10. android json相关