根据W3C的定义,Web Services(Web服务)是一个用于支持网络间不同机器互操作的软件系统,它是一种自包含、自描述和模块化的应用程序,它可以在网络中被描述、发布和调用,可以将它看作是基于网络的、分布式的模块化组件。
Web Services是建立在通用协议的基础之上,如HTTP、SOAP、UDDI、WSDL等,这些协议在操作系统、编程语言和对象模型的选择上没有任何倾向,因此有着很强的生命力。
Web Services的优势在于提供了不同应用程序平台之间的互操作,它使得基于组件的开发和Web相结合的效果达到最佳。它是基于HTTP协议的,调用请求和回应消息都可以穿过防火墙,不需要更改防火墙的设置,这样就避免了使用特殊端口进行通信时无法穿越防火墙的问题。
简单的理解:通常我们所说的WebService都是远程的某个服务器对外公开了某种服务,或者理解为对外公开了某个功能或者方法,而我们可以通过编程来调用该服务以获得我们需要的信息。例如:www.webxml.com.cn对外公开了手机号码归属地查询服务,我们只需要在调用该服务时传入一个手机号段(号码)就能立即获取该号段的归属地信息。
更通俗的理解:通过使用WebService,我们能够像调用本地方法一样去调用远程服务器上的方法。我们并不需要关心远程的那个方法是Java写的,还是PHP或C#写的;我们并不需要关心远程的方法是基于Unix平台,还是Windows平台,也就是说WebService与平台和语言无关。
说到WebSerivce,就必须要知道SOAP和WSDL,它们到底和WebSerice有着怎么的关系?上面已经提到,Web Services是建立在HTTP、SOAP、WSDL等通用协议的基础之上。
SOAP(Simple Object Access Protocol,简单对象访问协议)是一种轻量级的、简单的、基于XML的协议,被设计用于在分布式环境中交换格式化和固化信息的简单协议。也就是说,要进行通信,进行数据访问传输,就必须依赖于一定的协议,而SOAP正是WebService通信中所依赖的一种协议。目前经常使用的SOAP协议有两个版本:SOAP 1.1 和 SOAP 1.2。
WSDL(Web Services Description Language,即Web服务描述语言)是一种用来描述Web服务的XML语言,它描述了Web服务的功能、接口、参数、返回值等,便于用户绑定和调用服务。它以一种和具体语言无关的方式定义了给定Web服务调用和应答的相关操作和消息。
在开发天气预报的Android应用之前,首先需要找到一个可以对外提供天气预报的Web Service,通过搜索发现站点http://webservice.webxml.com.cn/WebServices/WeatherWS.asmx可以对外提供天气预报的Web Service,因此程序会调用此站点的Web Service来实现天气预报。(注意:如果该站点的天气预报Web Service服务已经停止,那么本程序将无法正常调用Web Service,那么天气预报的功能自然也就失效啦)
好啦,现在开始step by step地实现该应用程序。
第一步:获取并使用KSOAP包
在Android SDK中并没有提供调用WebService的库,因此,需要使用第三方的SDK来调用WebService。PC版本的WebService库非常丰富,但这些对Android来说过于庞大。适合手机的WebService客户端的SDK有一些,比较常用的是KSOAP2。
KSOAP2 地址:http://code.google.com/p/ksoap2-android/
我下载的最新的是: ksoap2-android-assembly-2.5.2-jar-with-dependencies.jar
第二步:编写调用Web Service的工具类 ServiceUtil.java
因为本程序主要需要调用如下三个Web Service操作:
a.获取省份:getRegionProvince方法
b.根据省份获取城市:getSupportCityString方法
c.根据城市获取天气:getWeather方法
为了让应用界面更加美观,可以访问http://www.webxml.com.cn/images/weather.zip下载各种天气图标,可以使用这些天气图标来美化应用。
package com.example.xiaocool.webservicedemo.Util; import org.ksoap2.SoapEnvelope; import org.ksoap2.serialization.SoapObject; import org.ksoap2.serialization.SoapSerializationEnvelope; import org.ksoap2.transport.HttpTransportSE; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.FutureTask; /** * Created by JustYu on 2015/4/20. */ public class ServiceUtil { //定义 Web Service 的命名空间 static final String SERVICE_NS = "http://WebXml.com.cn/"; //定义Web service 提供服务的URL static final String SERVICE_URL = "http://webservice.webxml.com.cn/WebServices/WeatherWS.asmx"; //调用 Web Service 获取省份列表 public static List<String> getProvinceList() { //调用的方法 final String methodName = "getRegionProvince"; //创建HttpTransportSE 传输对象 final HttpTransportSE ht = new HttpTransportSE(SERVICE_URL); ht.debug = true; //使用SOAP1.1 协议创建Envelop对象 final SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11); //实例化 SoapObject对象 SoapObject soapObject = new SoapObject(SERVICE_NS, methodName); envelope.bodyOut = soapObject; //设置.Net 提供的web service 保持较好的兼容性 envelope.dotNet = true; FutureTask<List<String>> task = new FutureTask<List<String>>( new Callable<List<String>>() { @Override public List<String> call() throws Exception { //调用Web Service ht.call(SERVICE_NS + methodName, envelope); if (envelope.getResponse() != null) { //获取服务器响应返回的SOAP消息 SoapObject result = (SoapObject) envelope.bodyIn; SoapObject detail = (SoapObject) result.getProperty(methodName + "Result"); //解析服务器响应的Soap return parseProvinceOrCity(detail); } return null; } } ); new Thread(task).start(); try { return task.get(); } catch (Exception e) { e.printStackTrace(); } return null; } //根据省份获取城市列表 public static List<String> getCityListByProvince(String province) { //调用的方法 final String methodName = "getSupportCityString"; //创建HttpTransportSe final HttpTransportSE ht = new HttpTransportSE(SERVICE_URL); ht.debug = true; //实例化SoapObject 对象 SoapObject soapObject = new SoapObject(SERVICE_NS, methodName); //添加一个请求参数 soapObject.addProperty("theRegionCode", province); //使用SOAP1.1 协议创建Envelop 对象 final SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11); envelope.bodyOut = soapObject; //设置与。Net 提供的WEB Sertvice 提供较好的兼容性 envelope.dotNet = true; FutureTask<List<String>> task = new FutureTask<List<String>>( new Callable<List<String>>() { @Override public List<String> call() throws Exception { //调用Web service ht.call(SERVICE_NS + methodName, envelope); if (envelope.getResponse() != null) { //获取服务器响应返回的SOAP消息 SoapObject result = (SoapObject) envelope.bodyIn; SoapObject detail = (SoapObject) result.getProperty(methodName + "Result"); //解析服务器响应的Soap 对象 return parseProvinceOrCity(detail); } return null; } } ); new Thread(task).start(); try { return task.get(); } catch (Exception e) { e.printStackTrace(); } return null; } private static List<String> parseProvinceOrCity(SoapObject detail) { ArrayList<String> result = new ArrayList<String>(); for (int i = 0; i < detail.getPropertyCount(); i++) { //解析出每个省份 result.add(detail.getProperty(i).toString().split(",")[0]); } return result; } public static SoapObject getWeatherByCity(String cityName) { final String methodName = "getWeather"; //创建HttpTransportSE 传输对象 final HttpTransportSE ht = new HttpTransportSE(SERVICE_URL); ht.debug = true; //使用Soap1.1协议创建 envelop对象 final SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11); SoapObject soapObject = new SoapObject(SERVICE_NS, methodName); //添加一个请求参数 soapObject.addProperty("theCityCode", cityName); envelope.bodyOut = soapObject; //设置与.net 提供的webservice 提供良好的兼容性 envelope.dotNet = true; FutureTask<SoapObject> task = new FutureTask<SoapObject>( new Callable<SoapObject>() { @Override public SoapObject call() throws Exception { //调用wenservice SERVICE_NS+methodName====SoapAction ht.call(SERVICE_NS + methodName, envelope); SoapObject result = (SoapObject) envelope.bodyIn; SoapObject detail = (SoapObject) result.getProperty(methodName + "Result"); return detail; } }); new Thread(task).start(); try { return task.get(); } catch (Exception e) { e.printStackTrace(); } return null; } }
第三步:设计应用的UI界面
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".MainActivity"> <!--省份列表--> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="10dp" android:text="省份" /> <Spinner android:id="@+id/province" android:layout_width="fill_parent" android:layout_height="wrap_content"></Spinner> </LinearLayout> <!--城市列表--> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="10dp" android:text="城市" /> <Spinner android:id="@+id/city" android:layout_width="fill_parent" android:layout_height="wrap_content"></Spinner> </LinearLayout> <!-- 显示今天天气的图片和文本框--> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <ImageView android:id="@+id/todayWhIcon1" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <ImageView android:id="@+id/todayWhIcon2" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <TextView android:id="@+id/weatherToday" android:layout_width="fill_parent" android:layout_height="wrap_content" /> </LinearLayout> <!-- 显示明天天气的图片和文本框--> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <ImageView android:id="@+id/tomorrowWhIcon1" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <ImageView android:id="@+id/tommorrowWhIcon2" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <TextView android:id="@+id/tommorroToday" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_weight="1" /> </LinearLayout> <!-- 显示明天天气的图片和文本框--> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <ImageView android:id="@+id/afterdayWhIcon1" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <ImageView android:id="@+id/afterdayWhIcon2" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <TextView android:id="@+id/afterdayToday" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_weight="1" /> </LinearLayout> <TextView android:id="@+id/weatherCurrent" android:layout_width="fill_parent" android:layout_height="wrap_content" /> </LinearLayout>
第四步:程序的主应用
package com.example.xiaocool.webservicedemo;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.Spinner;
import android.widget.TextView;
import com.example.xiaocool.webservicedemo.Util.ServiceUtil;
import org.ksoap2.serialization.SoapObject;
import java.util.List;
public class MainActivity extends ActionBarActivity {
private Spinner provinceSpinner;
private Spinner citySpinner;
private ImageView todayWhIcon1;
private ImageView todayWhIcon2;
private TextView TextWeatherToday;
private ImageView tommorrowWhIcon1;
private ImageView tommorrowWhIcon2;
private TextView TextWeathertommorrow;
private ImageView afterdayWhIcon1;
private ImageView afterdayWhIcon2;
private TextView TextWeatherafterday;
private TextView textWeatherCurrent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
provinceSpinner = (Spinner) this.findViewById(R.id.province);
citySpinner = (Spinner) this.findViewById(R.id.city);
todayWhIcon1 = (ImageView) this.findViewById(R.id.todayWhIcon1);
todayWhIcon2 = (ImageView) this.findViewById(R.id.todayWhIcon2);
TextWeatherToday = (TextView) this.findViewById(R.id.weatherToday);
tommorrowWhIcon1 = (ImageView) this.findViewById(R.id.tomorrowWhIcon1);
tommorrowWhIcon2 = (ImageView) this.findViewById(R.id.tommorrowWhIcon2);
TextWeathertommorrow = (TextView) this.findViewById(R.id.tommorroToday);
afterdayWhIcon1 = (ImageView) this.findViewById(R.id.afterdayWhIcon1);
afterdayWhIcon2 = (ImageView) this.findViewById(R.id.afterdayWhIcon2);
TextWeatherafterday = (TextView) this.findViewById(R.id.afterdayToday);
textWeatherCurrent = (TextView) this.findViewById(R.id.weatherCurrent);
//调用webservice 获取省份
List<String> provinces = ServiceUtil.getProvinceList();
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, provinces);
provinceSpinner.setAdapter(adapter);
//当省份的spinner 的选择项被改变时
provinceSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
List<String> citys=ServiceUtil.getCityListByProvince(provinceSpinner.getSelectedItem().toString());
ArrayAdapter<String> cityadapter = new ArrayAdapter<String>(MainActivity.this, android.R.layout.simple_spinner_item, citys);
citySpinner.setAdapter(cityadapter);
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
//当城市的Spinner 的选择项被改变是
citySpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
ShowWeather(citySpinner.getSelectedItem().toString());
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
}
private void ShowWeather(String city){
String weatherToday=null;
String weatherTomorrow=null;
String weatherAfterday=null;
String weatherCurrent=null;
int iconToday[]=new int[2];
int iconTomorrow[]=new int[2];
int iconAfterday[]=new int[2];
//获取远程WEB service 返回的对象
SoapObject detail=ServiceUtil.getWeatherByCity(city);
//获取天气情况
// weatherCurrent=detail.getProperty(4).toString();
//解析今天的天气
String date=detail.getProperty(7).toString();
weatherToday="今天:"+date.split(" ")[0];
weatherToday=weatherToday+"\n天气:"+date.split(" ")[1];
weatherToday=weatherToday+"\n气温:"+detail.getProperty(8).toString();
weatherToday=weatherToday+"\n风力:"+detail.getProperty(9).toString()+"\n";
//更新当天的天气情况
textWeatherCurrent.setText(weatherCurrent);
TextWeatherToday.setText(weatherToday);
}
}
第五步:添加访问网络的权限
注意:如果该站点的天气预报Web Service服务已经停止,那么本程序将无法正常调用Web Service,那么天气预报的功能自然也就失效啦
原文地址:http://xiaocool.blog.51cto.com/1593956/1638163