android:
layout_width="fill_parent"
android:
layout_height="fill_parent"
android:
background="#ffffff"
android:
textColor="#000000"
android:
id="@+id/pagetext"
/>
清单2展示了本示例使用的Java代码。
清单2.GetWebPage.java
packagecom.msi.getwebpage;
importandroid.app.Activity;
importandroid.os.Bundle;
//usedforinteractingwithuserinterface
importandroid.widget.Button;
importandroid.widget.TextView;
importandroid.widget.EditText;
importandroid.view.View;
//usedforpassingdata
importandroid.os.Handler;
importandroid.os.Message;
//usedforconnectivity
importjava.io.BufferedReader;
importjava.io.InputStreamReader;
import.URL;
import.URLConnection;
publicclassGetWebPageextendsActivity{
/**Calledwhentheactivityisfirstcreated.*/
Handlerh;
@Override
publicvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
finalEditTexteText=(EditText)findViewById(R.id.address);
finalTextViewtView=(TextView)findViewById(R.id.pagetext);
this.h=newHandler(){
@Override
publicvoidhandleMessage(Messagemsg){
//processincomingmessageshere
switch(msg.what){
case0:
tView.append((String)msg.obj);
break;
}
super.handleMessage(msg);
}
};
finalButtonbutton=(Button)findViewById(R.id.ButtonGo);
button.setOnClickListener(newButton.OnClickListener(){
publicvoidonClick(Viewv){
try{
tView.setText("");
//Performactiononclick
URLurl=newURL(eText.getText().toString());
URLConnectionconn=url.openConnection();
//Gettheresponse
BufferedReaderrd=newBufferedReader(new
InputStreamReader(conn.getInputStream()));
Stringline="";
while((line=rd.readLine())!
=null){
Messagelmsg;
lmsg=newMessage();
lmsg.obj=line;
lmsg.what=0;
GetWebPage.this.h.sendMessage(lmsg);
}
}
catch(Exceptione){
}
}
});
}
}
这些代码可以分解成一些常见的部分。
这里使用一些重要(必需)的导入语句来恰当地引用UI、数据传递以及应用程序中使用的与网络有关的类。
所有与网络相关的代码出现在 OnClickListener 的 OnClick 方法中。
在选择 图1 所示的标签为 go!
的按钮之后调用这些代码。
URL 和 URLConnection 类共同提供与用户所选的Web站点的连接。
BufferedReader 的一个实例负责从Web站点连接中读取传入的数据。
每读取一行代码,文本就被附加到一个TextView。
数据并没有直接指定给TextView(但是在本例中可以)。
我们引入了一种设计模式,即创建一个消息对象并将该对象发送到一个处理程序的实例。
这是更新UI的一种比较可取的方法,对可能需要同时运行多个线程的应用程序而言尤其如此。
在示例中,Android应用程序与HTTPWeb服务器进行通信,比如Apache或InternetInformationServer(IIS位于Microsoft®服务器上)。
如果应用程序直接与TCPsocket对话,那么您将以不同的方式实现应用程序。
清单3所示的代码片段展示了另一种与远程服务器交互的方式。
这个清单被实现为一个单独的线程。
清单3.Daytime客户机
publicclassRequesterextendsThread{
SocketrequestSocket;
Stringmessage;
StringBuilderreturnStringBuffer=newStringBuilder();
Messagelmsg;
intch;
@Override
publicvoidrun(){
try{
this.requestSocket=newSocket("",13);
InputStreamReaderisr=newInputStreamReader(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=newMessage();
this.lmsg.obj=this.message;
this.lmsg.what=0;
h.sendMessage(this.lmsg);
this.requestSocket.close();
}catch(Exceptionee){
Log.d("sampleapplication","failedtoreaddata"+ee.getMessage());
}
}
}
与前面的示例类似,上面的代码使用消息和处理程序方法来将数据发送给调用者,调用者将更新UI并执行后续处理。
与 清单1 不同,这个例子并没有与HTTP服务器通信,因此没有使用 URLConnection 类。
相反,使用了较低级的 Socket 类在端口13打开与远程服务器的基于流的socket连接。
端口13是典型的“DaytimeServer”应用程序。
DaytimeServer接受传入的socket连接并以文本的形式将日期和时间发送给调用socket。
一旦发送完数据,服务器将关闭socket。
示例也展示了 InputStreamReader 的使用和一个特定字符编码。
发送文本消息是您需要使用Android完成的另一项任务。
清单4展示了一个示例。
清单4.发送一条文本消息
voidsendMessage(Stringrecipient,StringmyMessage){
SmsManagersm=SmsManager.getDefault();
sm.sendTextMessage("destinationnumber",null,"hellothere",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电话(比如TMobileG1)之间使用的协议可以是HTTP或私有协定。
在控制器和配备Android的设备之间发送的数据将是表示以下内容的基本数据:
∙出现漏水
∙当前温度
∙消耗的功率
∙可能包含一些通用的类似数据和数字值
为什么需要关注消耗的功率?
一个可能的原因就是有些人忘记关闭机器,因此电费单上的数字会一直增长。
第二个理由有些复杂:
假设您有一台非常大的冰箱,并且电源可能已被关闭。
那么情况就复杂了,而且处理起来也需要很高的代价。
或者,空调设备的断路器出现故障,因此机房无法保持恒定的温度。
基本的设计看上去是可行的。
如果使用的是Android,那么可以使用任何移动平台来替换 图2 中的Android。
但如果使用配备了Android的设备替换微控制器,那应该怎么做呢?
下一节将讨论对这个应用程序的扩展以及通过使用Android而启用的特性。
回页首
扩展应用程序
本文的第一个架构以一个微控制器为中心。
微控制器可分为不同的外形和大小,从Microchip的6pin“10F”到添加了外围设备、pin和代码空间的32位大型微控制器。
如果使用Android取代传统的微控制器放到设备中,会怎么样?
对于某些应用程序而言,在成本方面是不可取的,但是根据图3的判断,这种方法也是可行的。
图3.在设备中使用Android的可能架构
使用嵌入式的方式部署Android为您提供了更加丰富的编程环境。
您可以和以前一样继续监视湿度、温度和功率消耗特征,同时还可以观察到记录音频、视频和振动。
您将拥有一个微报警、访问控制系统,以及一个环节监控工具。
由于Android已经可以实现联网,您不需要使用控制器PC就可以实现监控并与网络直接对话。
这种方法还为现场更新软件提供了额外的好处。
假设您希望为监控软件添加新的特性(或修复bug)。
如果使用传统的微控制器方法,那么任务执行起来将十分繁琐并且代价昂贵,甚至根本不可能实现。
而对于Android而言,您可以获得更整洁的部署模型并拥有更好的灵活性。
Android如今主要运行在移动手机中,但是它已经被移植到NetBooks和其他平台上。
希望本文为您提供了一些好的思考内容。
我现在该去运行我的系统了。
您永远也不会知道下一次热水器漏水会在什么时候发生。
回页首
结束语
在本文中,我们大体介绍了Android的联网功能。
您了解了一些自己可以创建的样例应用程序,包括与Web服务器交互和发送文本消息。
您看到了如何将Android连接到一个真实的环境监控系统。
通过代码示例,您了解到应该在什么时候将Android扩展到一些特殊应用程序中,比如嵌入式控制器。
请继续关注我的下一篇文章,它将介绍如何使用基于Android的电话构建一个婴儿监控系统。