11 工程示例一搜搜问问注本科生的毕业设计.docx
- 文档编号:8649051
- 上传时间:2023-02-01
- 格式:DOCX
- 页数:25
- 大小:302.96KB
11 工程示例一搜搜问问注本科生的毕业设计.docx
《11 工程示例一搜搜问问注本科生的毕业设计.docx》由会员分享,可在线阅读,更多相关《11 工程示例一搜搜问问注本科生的毕业设计.docx(25页珍藏版)》请在冰豆网上搜索。
11工程示例一搜搜问问注本科生的毕业设计
第十一章搜搜问问:
基于Android操作系统的智能手机软件开发与应用
GoogleAndroid无论是在网络编程方面,还是本地数据存储方面都提供了强大的API,这使得Android应用程序开发变得简单,快速。
同时,这也是Android系统迅速发展的原因之一。
本章所介绍的程序的主要成果则是利用Android强大的API开发一款手机搜索软件,供人们查询平时遇到的生涩词汇。
在本章开始部分我们先来介绍一点网络编程方面的知识。
11.1基于KSoap、HttpClient、WebView的网络编程
1.基于KSoap的网络通信
1)KSoap概述
KSoap2-Android是Android平台上一个高效、轻型的SOAP开发包。
它是KSoap2协议家族中专门为Android平台开发的一种网络协议。
其中增加了一些重要的特性和增强功能,而这些特点都将使网络开发无论是对于专业开发人员还是业余爱好者变得更加轻松。
对于J2ME访问远端的WebService,我们还有两种协议可供选择:
●Wingfoot
●KSOAP
其中Wingfoot是由WingfootSoftware出品的一款J2MESOAP1.1的轻量级实现方案。
KSOAP是Enhydra.org的一个开源作品。
基于Enhydra.org的开源通用XML解析器为KXML,KSOAP2完成了J2ME/MIDP平台上的SOAP解析和调用工作。
StefanHaustein领导的KSOAP开发小组在2001年5月17日推出了KSOAPAlhpa版本。
之后又经过了一年,推出了KSOAP1.2。
2003年8月25日又推出了KSOAP2协议,对SOAP序列化规范支持得更好。
KSOAP虽然在2003年8月之后就不再维护了,但由于它的开源性,很容易加入增强特性,比如说在默认情况下KSOAP2仅仅支持cmnet接入点,但可以修改KSOAP2的HttpTransport.Java代码增加对cmwap接入点的支持。
2)kSOAP2接口
org.ksoap2.SoapEnvelope
org.ksoap2.SoapSerializationEnvelope
org.ksoap2.SoapObject
org.ksoap2.transport.HttpTransport
SoapEnvelope对应于SOAP规范中的SOAPEnvelope,其中封装了head和body对象。
SoapSerializationEnvelope是KSOAP2新增加的类,是对SoapEnvelope的一种扩展,对SOAP序列化格式规范提供了支持,能够对简单对象自动进行序列化的规范。
SoapObject让你自如地构造SOAP调用;
KSOAP中的HttpTransport为使用者屏蔽了Internet访问/请求和获取服务器SOAP的细节问题。
下面通过一个简单的webservice调用,来理解一下KSOAP是如何做到SOAP解析的:
KSOAP和WebService之间传递String。
Webservice传递String给MIDP是一件很简单的事情。
首先在服务器端,不管是用MicrosftASP.NET创建webservice,还是由tomcat+AXIS1.2支撑的webservice都可以这样来编写主服务类:
服务器端代码:
publicclassSimpleKSoapWS{
publicSimpleKSoapWS(){}
publicStringfoo(Stringusername,Stringpassword)
{
return“fooResult”;}
}
KSOAP调用WebService过程:
首先要使用SoapObject类,这是一个高度抽象化的类,用来完成SOAP调用。
可以调用它的addProperty()方法填写要调用的WebService中的方法参数。
如下面代码所示:
SoapObjectrequest =newSoapObject(serviceNamespace,methodName);
SoapObject构造函数的两个参数含义分别为:
serviceNamespace是webservice的命名空间,methodName则是要调用webservice的方法名字。
然后,按照webservice方法设置参数的顺序,依次调用下面所示来填充webservice参数。
request.addProperty("username","user");
request.addProperty("password","pass");
然后让SoapSerializationEnvelope把构造好的SoapObject封装进去,代码如下:
SoapSerializationEnvelopeenvelope=newSoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.bodyOut=request;
其中可以通过SoapSerializationEnvelope或者SoapEnvelope构造函数来指明要用KSOAP的哪一种规范,可以是以下几种中的一种:
常量SoapEnvelope.VER10:
对应于SOAP1.0规范。
常量SoapEnvelope.VER11:
对应于SOAP1.1规范。
常量SoapEnvelope.VER12:
对应于SOAP1.2规范。
接下来就要声明:
HttpTransporttx=newHttpTransport(serviceURL);
ht.debug=true;
serviceURL是要投递SOAP数据的目标地址
HttpTransport是一个非常强大的辅助功能类,来完成Http-call,它封装了网络请求的一切信息,因此开发者完全不用考虑序列化消息的细节。
并且可以通过设置它的debug属性为true来打开调试信息。
方法HttpTransport.call()能够发送请求给服务器、并且接收服务器响应的序列化SOAP消息,代码如下所示:
ht.call(null,envelope);
HttpTransport的call方法的两个参数含义分别为:
soapActionSOAP规范定义了一个名为SOAPAction的新的HTTP标头,所有SOAPHTTP请求都必须包含该标头。
SOAPAction标头旨在标明该消息的意图等。
通常可以置此参数为null,这样HttpTransport就会默认设置为HTTP标头,SOAPAction为空字符串。
其中Envelope就是前面我们已经构造好的SoapSerializationEnvelope或SoapEnvelope对象实例。
对于HttpTransport的处理上,kSOAP2和kSOAP1.2的写法不一样。
对于KSOAP1.2,HttpTransport的构造函数HttpTransport(Stringurl,StringsoapAction)中第二个参数soapAction是要调用的webservice方法名。
但是在KSOAP2中,构造函数却变成了HttpTransport(Stringurl)。
KSOAP2相当于把webservice方法名分离出来了,完全交给了SoapObject去封装,而HttpTransport实例仅仅负责把SoapEnvelope发送出去并接收webservice响应。
然后,调用call()方法是一个同步过程,需要等待webservice返回数据。
返回之后,就可以调用SoapSerializationEnvelope的getResult()方法来获取传回的结果了,代码如下:
ObjectResponse=envelope.getResult();
如果HttpTransport的debug属性设置为true,那么此时就可以通过。
System.out.println("Responsedump>>"+tx.responseDump);
打印出HttpTransport的调试信息。
综上所述,Android客户端的MIDlet按键事件函数可以编写为:
importorg.ksoap2.SoapEnvelope;
importorg.ksoap2.serialization.SoapObject;
importorg.ksoap2.serialization.SoapSerializationEnvelope;
importorg.ksoap2.transport.HttpTransport;
publicvoidcommandAction(Commandc,Displayables)
{
if(c==exitCommand)
{
destroyApp(false);
notifyDestroyed();
}
if(c==connectCommand)
{
//匿名内部Thread,调用kSOAP2访问远程服务。
ThreadwebserviceThread=newThread()
{
publicvoidrun()
{
try{
StringserviceNamespace="http:
//localhost:
8080/SimpleWS/services/SimpleKSoapWS";
StringmethodName="foo";
StringserviceURL="http:
//localhost:
8080/SimpleWS/services/SimpleKSoapWS";
SoapObjectrequest=newSoapObject(serviceNamespace,methodName);
request.addProperty("username","user");
request.addProperty("password","pass");
SoapSerializationEnvelopeenvelope=
newSoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.bodyOut=request;
HttpTransporttx=newHttpTransport(serviceURL);
ht.debug=true;
ht.call(null,envelope);
ObjectResponse=envelope.getResult();
System.out.println("dump>>"+tx.responseDump);
StringsResponse=(String)Response;
}catch(Exceptione){
e.printStackTrace();
}
}
};
webserviceThread.Start();
}
2.ApacheHttpClient客户端
由于ApacheHttpClient也是一个开源项目,弥补了灵活性不足的缺点,为客户端的HTTP编程提供了高效、功能丰富的工具包支持。
Android平台引入了ApacheHttpClient的同时还对它进行了一些封装和扩展,例如,设置了缺省的HTTP超时限制和缓存大小等功能。
HttpClient提供的主要的功能有:
实现了所有HTTP的方法,支持自动转向,支持HTTPS协议,支持代理服务器等。
HttpClient基本功能的使用:
GET方法:
使用HttpClient类需要以下6个步骤:
1.创建HttpClient的实例。
2.创建某种连接方法的实例,这里是GetMethod。
在GetMethod的构造函数中传入待连接的地址。
3.调用第一步中创建好的实例的execute方法来执行第二步中创建好的Gmethod实例。
4.读取response获取结果。
5.释放连接。
无论执行方法是否成功,都必须释放连接。
6.对得到后的内容进行分析处理。
根据以上步骤,来编写GET方法,用此种方法来取得某网页内容的代码。
而且大部分情况下HttpClient默认的构造函数已经足够使用。
HttpClienthttpClient=newHttpClient();
创建GET类的实例。
在GET方法的构造函数中传入要连接的地址。
GetMethod将会自动处理转发过程,若想要把自动处理转发过程去掉的话,可以调用方法setFollowRedirects(false)来实现。
GetMethodgetMethod=newGetMethod("
调用httpClient实例的executeMethod()方法来执行getMethod。
由于是执行网络上的程序,在执行executeMethod方法时,需要处理两个异常,分别为HttpException和IOException。
引起第一种异常的原因可能是在构造getMethod的时传入的协议不对,例如马虎将"http"写成"htp",或者服务器端返回的内容不对等,并且该异常发生后是不可恢复的;第二种异常通常是由于网络原因引起的,对于这种异常,HttpClient会根据指定的恢复策略自动来试着重新执行executeMethod()方法。
HttpClient的恢复策略可以通过自定义实现接口HttpMethodRetryHandler来实现。
同时,通过httpClient的方法setParameter()来设置你要实现的恢复策略,一般使用的是系统提供的默认恢复策略,该策略在碰到第二类异常的时候将自动重新执行3次。
executeMethod返回值是一个整数,表示执行该方法后服务器返回的状态码,该状态码能表示出该方法执行是否成功、需要认证或者页面发生了跳转等情况。
如果设置成了默认的恢复策略,在发生异常时候将自动重试执行3次,在这里开发者也可以设置自定义的恢复策略。
getMethod.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,newDefaultHttpMethodRetryHandler());
//执行getMethod
intstatusCode=client.executeMethod(getMethod);
if(statusCode!
=HttpStatus.SC_OK){
System.err.println("Methodfailed:
"+getMethod.getStatusLine());
}
在返回的状态码正确后,即可取得所要的内容。
取得目标地址的内容有三种方法,分别为:
第一种getResponseBody方法,该方法返回的是目标的二进制的byte流文件;第二种getResponseBodyAsString方法,这个方法返回的是String类型的数值,值得注意的是该方法返回的String的编码是根据系统默认的编码方式,所以返回的String值可能编码类型有误;第三种getResponseBodyAsStream方法,当目标地址中有大量数据需要传输时这种方法是最佳的方法。
以下代码使用了最简单的getResponseBody方法。
byte[]responseBody=method.getResponseBody();
释放连接。
无论执行是否成功,都必须释放连接。
method.releaseConnection();
处理内容。
在这一步中根据你的需要来处理收到的内容,在此例子中只是简单的将内容打印到控制台而已。
System.out.println(newString(responseBody));
POST方法:
根据RFC2616,对POST的解释如下:
POST方法用来向目的服务器发出请求,要求它接受被附在请求后的实体,并把它当作请求队列(Request-Line)中请求URI所指定资源的附加新子项。
POST被设计成用统一的方法实现下列功能:
对现有资源的注释(Annotationofexistingresources)。
向电子公告栏、新闻组,邮件列表或类似讨论组发送消息。
提交数据块,如将表单的结果提交给数据处理过程。
通过附加操作来扩展数据库。
调用HttpClient中的PostMethod与GetMethod极其类似,除了设置PostMethod的实例与GetMethod有些不同之外,剩下的步骤都很相似。
以下用登录清华大学BBS为例子进行代码的说明。
构造PostMethod之前的步骤与GetMethod之前的步骤是一样,构造PostMethod也需要一个URI参数,登录的地址是在创建了PostMethod的实例后,需要给method实例填充表单的值,在BBS的登录表单中需要有两个域,第一个是用户名id,第二个是密码password。
表单中的域类NameValuePair用来表示该类的构造函数第一个参数是域名,第二参数是该域的值;将表单所有的值设置到PostMethod中用方法setRequestBody实例中。
另外由于BBS登录成功后会自动转向另外一个页面,但是此时HttpClient对于要求接受后继服务的请求,比如POST和PUT,并不支持自动转发,因此需要开发者自己对页面做转向处理。
具体的页面转向处理参见代码如下:
Stringurl="
PostMethodpostMethod=newPostMethod(url);
//填入各个表单域的值
NameValuePair[]data={newNameValuePair("id","youUserName"),
newNameValuePair("passwd","yourPwd")};
//将表单的值放入postMethod中
postMethod.setRequestBody(data);
//执行postMethod
intstatusCode=httpClient.executeMethod(postMethod);
//HttpClient对于要求接受后继服务的请求,象POST和PUT等不能自动处理转发
//301或者302
if(statusCode==HttpStatus.SC_MOVED_PERMANENTLY)
statusCode==HttpStatus.SC_MOVED_TEMPORARILY){
//从头中取出转向的地址
HeaderlocationHeader=postMethod.getResponseHeader("location");
Stringlocation=null;
if(locationHeader!
=null){
location=locationHeader.getValue();
System.out.println("Thepagewasredirectedto:
"+location);
}else{
System.err.println("Locationfieldvalueisnull.");
}
return;
}
使用HttpClient过程中遇到的一些问题:
字符编码问题:
某目标页的编码可能出现在两个地方,第一个地方是服务器返回的http头中,另外一个地方则是得到的html/xml页面中。
在http头的Content-Type字段中可能会包含字符编码信息。
例如可能返回的头会包含这样的信息:
Content-Type:
text/html;charset=UTF-8。
这个头信息表明该页的编码是UTF-8格式,但是服务器返回的头信息未必能与内容匹配上。
比如对于一些双字节语言的国家,可能服务器返回的编码类型是UTF-8,但真正的内容却不是由UTF-8来编码的,因此需要在另外的地方去获得页面的编码信息;但是如果服务器返回的编码不是UTF-8格式的,而是一些具体的编码,比如gb2312等形式,那服务器返回的可能就是正确的编码信息。
通过method对象的getResponseCharSet()方法可以得到http头中正确的编码信息。
对于xml或者html这样的文件,是允许作者在页面中直接指定编码类型的。
比如在html有
xmlversion="1.0"encoding="gb2312"?
>这样的标签,这些情况下,可能与http头中返回的编码信息冲突,需要用户自己判断到底哪种编码类型是真正的编码。
自动转向问题:
根据RFC2616对自动转向的定义,主要有两种:
301和302。
301表示永久的移走,当返回的是301,则表示请求的资源已经被转移到一个固定的地方,任何向该地址发起的请求都会被自动转到新的地址上。
302表示暂时的转向,比如在服务器端servlet程序调用sendRedirect方法后,在客户端就会得到一个值为302的代码,这时服务器返回的头信息中location的值就是sendRedirect转向的暂时的目标地址。
HttpClient支持自动转向处理,但是像POST和PUT方式这种要求接受后继服务的请求方式,暂时不支持自动转向功能,因此在碰到POST方式提交后返回的是301或者302的话,就需要开发者编写代码进行处理。
类似于刚才在POSTMethod中举的例子一样:
如果想要进入BBS后的页面,必须重新发起登录的请求,请求的新地址可以在头字段的location中得到。
值得注意的是,有时location返回的可能是相对路径,此时需要对location返回的值做一些处理后,才可以发起向新地址的请求。
另外除了在头中包含的信息可能使页面发生重定向外,在页面中也有可能会发生页面的重定向。
其中引起页面自动转向的标签是:
3.WebView组件 在Android手机中内置了一款高性能webkit内核的开源浏览器,在SDK中封装为一个叫做WebView的应用组件。 WebKit是MacOSXv10.3及以上版本所包含的软件框架。 同时,W
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 11 工程示例一搜搜问问注本科生的毕业设计 工程 示例 一搜搜 问问 本科生 毕业设计