第十五章:Android 调用WebService(.net平台)
什么是webservice?
Web service是一个平台独立的,低耦合的,自包含的、基于可编程的web的应用程序,可使用开放的XML(标准通用标记语言下的一个子集)标准来描述、发布、发现、协调和配置这些应用程序,用于开发分布式的互操作的应用程序。Web Service所使用的是Internet上统一、开放的标准,如HTTP、XML、SOAP(简单对象访问协议)、WSDL(webservice描述语言)等,所以Web Service可以在任何支持这些标准的环境(Windows,Linux)中使用。(说白了,webService就像是一个方法,只不过不是你自己写的,而且是跨语言、跨平台的。我们只需要调用这个方法获得返回结果即可。至于webservice怎么运行的与调用端是无关的,也不需要知道)
注:SOAP协议(Simple Object Access Protocal,简单对象访问协议),它是一个用于分散和分布式环境下网络信息交换的基于XML的通讯协议。在此协议下,软件组件或应用程序能够通过标准的HTTP协议进行通讯。它的设计目标就是简单性和扩展性,这有助于大量异构程序和平台之间的互操作性,从而使存在的应用程序能够被广泛的用户访问。
为什么要使用webservice?
方便并且开放。大家都知道,在手机上的cpu和内存等条件是很有限的,尤其是处理一些大数据等易耗损资源的操作都会非常吃力甚至根本就不行。因此,将这一部分的处理交给服务器端,让服务器来处理这些数据。那么在服务器端我们就可以实现一个webservice让我们在客户端来调用,返回我们需要的数据即可。
什么时候使用webservice?
只要是数据交换都可以使用。但是对webservice的优劣要有认识:
优点:
- 跨平台、跨语言;
- SOAP协议是基于XML和HTTP这些业界的标准的,得到了所有的重要公司的支持。
- 由于使用了SOAP,数据是以ASCII文本的方式而非二进制传输,调试很方便;并且由于这样,它的数据容易通过防火墙,不需要防火墙为了程序而单独开一个“漏洞”。
- WebService实现的技术难度要比CORBA和DCOM小得多。
- 要实现B2B集成,EDI比较完善与比较复杂;而用WebService则可以低成本的实现,小公司也可以用上。
- 在C/S的程序中,WebService可以实现网页无整体刷新的与服务器打交道并取数。
缺点:
- WebService使用了XML对数据封装,会造成大量的数据要在网络中传输。
- WebService规范没有规定任何与实现相关的细节,包括对象模型、编程语言,这一点,它不如CORBA 。
怎么使用webservice?(整个过程我们用一个获取手机号归属地的例子来说明)
要使用webservice就必须知道webservice的接口文档,即WSDL(webservice描述服务)。那么,WSDL究竟长成什么样子呢?
下面我给出了一个链接:(该链接打开就是一个WSDL)
http://webservice.webxml.com.cn/WebServices/MobileCodeWS.asmx?wsdl
打开后如下图所示:(未显示完整)
家一看就傻眼了吧,怎么多的信息,到底哪些是我们需要的呢?
其实,我们调用webservice只需要三个数据即可:命名空间、方法名称(包括方法名和参数类型)、根节点。
那么WSDL上对应的数据在哪里呢?
根节点即是上面给出的链接去掉“?wsdl”:http://webservice.webxml.com.cn/WebServices/MobileCodeWS.asmx
命名空间、方法名称(包括方法名和参数类型)在下图中依次为从上到下,从左到右。
好了,知道了这些。我们就可以开始开工了。
首先,我们需要下载一个ksoap2jar包,它是我们调用webservice的工具类,在此给出一个下载地址:http://download.csdn.net/detail/af74776/7735251
下载好jar包后导入进项目中(先复制到libs文件夹下,点击jar包,单击右键,选择build path ,然后选择add External Archives。然后,单击工程项目,单击右键,选择build path ,再选择configure build pathxxxxx。在弹出的对话框的右侧,选择Order and Export选项卡。在刚刚添加的ksoap2 jar包前打钩,然后选择ok即可)
如下:
成功导入包后,便可开始编写代码了(哎,直接上代码吧。代码上有详细的注解):
布局文件activity_web_service.xml:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" android:paddingLeft="5dip" android:paddingRight="5dip" android:paddingTop="5dip" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="手机号码(段):" /> <EditText android:id="@+id/phone_sec" android:layout_width="fill_parent" android:layout_height="wrap_content" android:hint="例如:1398547" android:inputType="textPhonetic" android:singleLine="true" /> <Button android:id="@+id/query_btn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="right" android:text="查询" /> <TextView android:id="@+id/result_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal|center_vertical" /> </LinearLayout>
WebServiceActivity.java:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.example.helloandroid; import android.app.Activity; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; import org.ksoap2.SoapEnvelope; import org.ksoap2.serialization.SoapObject; import org.ksoap2.serialization.SoapSerializationEnvelope; //import org.ksoap2.transport.AndroidHttpTransport; import org.ksoap2.transport.HttpTransportSE; public class WebServiceActivity extends Activity { private EditText phoneSecEditText; private TextView resultView; private Button queryButton; String result; private String phoneSec; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_web_service); phoneSecEditText = (EditText) findViewById(R.id.phone_sec); resultView = (TextView) findViewById(R.id.result_text); queryButton = (Button) findViewById(R.id.query_btn); queryButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { phoneSec = phoneSecEditText.getText().toString().trim(); // 简单判断用户输入的手机号码(段)是否合法 if ("".equals(phoneSec) || phoneSec.length() < 7) { // 给出错误提示 phoneSecEditText.setError("您输入的手机号码(段)有误!"); phoneSecEditText.requestFocus(); // 将显示查询结果的TextView清空 resultView.setText(""); return; } //Android4.0以后便不可以在主线程中访问网络了,因此要新开线程 Runnable r = new NetWorkHandler(); Thread thread = new Thread(r); thread.start(); // 由于网络连接需要一定时间,为了在主界面上进行网络信息的展现,暂时用sleep()方法简单实现,使主线程等待网络信息读取完成。 try { Thread.sleep(300); } catch (InterruptedException e) { e.printStackTrace(); } if (result != null) { resultView.setText(result); } } }); } /** * 手机号段归属查询 * * @param phoneSec手机号段 */ private void getRemoteInfo(String phoneSec) { // 命名空间 String nameSpace = "http://WebXml.com.cn/"; // 调用的方法名称 String methodName = "getMobileCodeInfo"; // EndPoint String endPoint = "http://webservice.webxml.com.cn/WebServices/MobileCodeWS.asmx"; // SOAP Action 为命名空间+方法名称 String soapAction = "http://WebXml.com.cn/getMobileCodeInfo"; // 指定WebService的命名空间和调用的方法名 SoapObject rpc = new SoapObject(nameSpace, methodName); // 设置需调用WebService接口需要传入的两个参数mobileCode、userId rpc.addProperty("mobileCode", phoneSec); rpc.addProperty("userId", ""); // 生成调用WebService方法的SOAP请求信息,并指定SOAP的版本 SoapSerializationEnvelope envelope = new SoapSerializationEnvelope( SoapEnvelope.VER12); envelope.bodyOut = rpc; // 设置是否调用的是dotNet开发的WebService envelope.dotNet = true; // 等价于envelope.bodyOut = rpc; envelope.setOutputSoapObject(rpc); HttpTransportSE transport = new HttpTransportSE(endPoint); try { // 调用WebService transport.call(soapAction, envelope); } catch (Exception e) { e.printStackTrace(); System.out.println("调用webservice异常"); } // 获取返回的数据 SoapObject object = (SoapObject) envelope.bodyIn; if (object != null) // 获取返回的结果 result = object.getProperty(0).toString(); else { System.out.println("object为空"); } } private class NetWorkHandler implements Runnable { @Override public void run() { getRemoteInfo(phoneSec); } } }
注意:千万不要忘记在清单文件中加上权限<uses-permission android:name="android.permission.INTERNET" />
当然,从程序严谨的角度来讲最好再加上手机是否连网的判断。
该例子在wifi环境下测试无异常,不保证在使用流量的情况下也正常。最后的效果如下图: