Java本身提供丰富的Web Service支持,比如说sun公司制定的JAX-WS 2 规范,还有Apache开源组织所提供的Axis1,Axis2,CXF等,这些技术不仅可以用于方便的对外提供Web Service,也可以用于简化Web Service的客户端编程。WebService是一种基于SOAP协议的远程调用标准,对于这个协议理解不深,知道webservice可以将不同操作系统平台、不同语言、不同技术整合到一块,android SDK没有直接调用webservice的库,最常用的是借助ksoap2-android这个第三方SDK。
对于手机等小型设备,他们的计算资源,存储资源都十分有限,因此android应用不大可能需要对外提供Web Service,Android应用通常只是充当Web Service的客户端,调用远程Web Service。
Google为Android平台开发Web Service客户端提供了ksoap2-android项目。下载ksoap2-android,点击这里下载jar包http://code.google.com/p/ksoap2-android/。
将下载好的JAR包添加到项目中的lib目录下,就可以借助ksoap2-android项目来调用Web Service所暴露的操作。
使用ksoap2-android调用Web Service操作的步骤如下:
1.创建HttpTransportSE传输对象:HttpTransportSE ht = new HttpTransportSE(SERVICE_URL); SERVICE_URL是webservice提供服务的url
2.使用SOAP1.1协议创建Envelop对象:SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11); 设置SOAP协议的版本号,根据服务端WebService的版本号设置。
3.实例化SoapObject对象:SoapObject soapObject = new SoapObject(SERVICE_NAMESPACE, methodName); 第一个参数表示WebService的命名空间,可以从WSDL文档中找到WebService的命名空间。第二个参数表示要调用的WebService方法名。
4.设置调用方法的参数值,如果没有参数,可以省略:例如soapObject.addProperty("theCityCode", cityName);
5.记得设置bodyout属性 envelope.bodyOut = soapObject;
6.调用webservice:ht.call(SERVICE_NAMESPACE+methodName, envelope);
7.获取服务器响应返回的SOAP消息:
SoapObject result = (SoapObject) envelope.bodyIn;
SoapObject detail = (SoapObject) result.getProperty(methodName+"Result");
在开发天气预报的应用之前,首先需要找到一个可以对外提供天气预报的Web Service,暂且使用网络免费的WebService这个可以http://webservice.webxml.com.cn/WebServices/WeatherWS.asmx
访问http://webservice.webxml.com.cn/WebServices/WeatherWS.asmx?wsdl,可以看到WSDL文档。
通过WSDL文档可以查看到调用Web Service的必要信息。
本程序主要需要调用如下三个Web Service操作:
1.获取省份
2.根据省份获取城市
3.根据城市获取天气
/** * */ package org.crazyit.net; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.FutureTask; import org.ksoap2.SoapEnvelope; import org.ksoap2.serialization.SoapObject; import org.ksoap2.serialization.SoapSerializationEnvelope; import org.ksoap2.transport.HttpTransportSE; public class WebServiceUtil { // 定义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 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; } 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"; final HttpTransportSE ht = new HttpTransportSE(SERVICE_URL); ht.debug = true; final SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11); SoapObject soapObject = new SoapObject(SERVICE_NS, methodName); soapObject.addProperty("theCityCode", cityName); envelope.bodyOut = soapObject; // 设置与.Net提供的Web Service保持较好的兼容性 envelope.dotNet = true; FutureTask<SoapObject> task = new FutureTask<SoapObject>( new Callable<SoapObject>() { @Override public SoapObject call() throws Exception { 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; } }
该程序的界面布局代码如下:
<?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="wrap_content" android:orientation="vertical" > <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:hint="@string/province" /> <!-- 让用户选择省份的Spinner --> <Spinner android:id="@+id/province" android:layout_width="fill_parent" android:layout_height="wrap_content" /> </LinearLayout> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:hint="@string/city" /> <!-- 让用户选择城市的Spinner --> <Spinner android:id="@+id/city" android:layout_width="fill_parent" android:layout_height="wrap_content" /> </LinearLayout> <!-- 显示今天天气的图片和文本框 --> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" > <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" android:layout_weight="1" /> </LinearLayout> <!-- 显示明天天气的图片和文本框 --> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" > <ImageView android:id="@+id/tomorrowWhIcon1" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <ImageView android:id="@+id/tomorrowWhIcon2" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <TextView android:id="@+id/weatherTomorrow" 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" > <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/weatherAfterday" 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 org.crazyit.net; import java.util.List; import org.crazyit.net.R; import org.ksoap2.serialization.SoapObject; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.widget.AdapterView; import android.widget.ImageView; import android.widget.Spinner; import android.widget.TextView; import android.widget.AdapterView.OnItemSelectedListener; public class MyWeather extends Activity { private Spinner provinceSpinner; private Spinner citySpinner; private ImageView todayWhIcon1; private ImageView todayWhIcon2; private TextView textWeatherToday; private ImageView tomorrowWhIcon1; private ImageView tomorrowWhIcon2; private TextView textWeatherTomorrow; private ImageView afterdayWhIcon1; private ImageView afterdayWhIcon2; private TextView textWeatherAfterday; private TextView textWeatherCurrent; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); todayWhIcon1 = (ImageView) findViewById(R.id.todayWhIcon1); todayWhIcon2 = (ImageView) findViewById(R.id.todayWhIcon2); textWeatherToday = (TextView) findViewById(R.id.weatherToday); tomorrowWhIcon1 = (ImageView) findViewById(R.id.tomorrowWhIcon1); tomorrowWhIcon2 = (ImageView) findViewById(R.id.tomorrowWhIcon2); textWeatherTomorrow = (TextView) findViewById(R.id.weatherTomorrow); afterdayWhIcon1 = (ImageView) findViewById(R.id.afterdayWhIcon1); afterdayWhIcon2 = (ImageView) findViewById(R.id.afterdayWhIcon2); textWeatherAfterday = (TextView) findViewById(R.id.weatherAfterday); textWeatherCurrent = (TextView) findViewById(R.id.weatherCurrent); // 获取程序界面中选择省份、城市的Spinner组件 provinceSpinner = (Spinner) findViewById(R.id.province); citySpinner = (Spinner) findViewById(R.id.city); // 调用远程Web Service获取省份列表 List<String> provinces = WebServiceUtil.getProvinceList(); ListAdapter adapter = new ListAdapter(this, provinces); // 使用Spinner显示省份列表 provinceSpinner.setAdapter(adapter); // 当省份Spinner的选择项被改变时 provinceSpinner.setOnItemSelectedListener(new OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> source, View parent, int position, long id) { List<String> cities = WebServiceUtil .getCityListByProvince(provinceSpinner.getSelectedItem() .toString()); ListAdapter cityAdapter = new ListAdapter(MyWeather.this, cities); // 使用Spinner显示城市列表 citySpinner.setAdapter(cityAdapter); } @Override public void onNothingSelected(AdapterView<?> arg0) { } }); // 当城市Spinner的选择项被改变时 citySpinner.setOnItemSelectedListener(new OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> source, View parent, int position, long id) { showWeather(citySpinner.getSelectedItem().toString()); } @Override public void onNothingSelected(AdapterView<?> arg0) { } }); } 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 = WebServiceUtil.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"; iconToday[0] = parseIcon(detail.getProperty(10).toString()); iconToday[1] = parseIcon(detail.getProperty(11).toString()); // 解析明天的天气情况 date = detail.getProperty(12).toString(); weatherTomorrow = "明天:" + date.split(" ")[0]; weatherTomorrow = weatherTomorrow + "\n天气:" + date.split(" ")[1]; weatherTomorrow = weatherTomorrow + "\n气温:" + detail.getProperty(13).toString(); weatherTomorrow = weatherTomorrow + "\n风力:" + detail.getProperty(14).toString() + "\n"; iconTomorrow[0] = parseIcon(detail.getProperty(15).toString()); iconTomorrow[1] = parseIcon(detail.getProperty(16).toString()); // 解析后天的天气情况 date = detail.getProperty(17).toString(); weatherAfterday = "后天:" + date.split(" ")[0]; weatherAfterday = weatherAfterday + "\n天气:" + date.split(" ")[1]; weatherAfterday = weatherAfterday + "\n气温:" + detail.getProperty(18).toString(); weatherAfterday = weatherAfterday + "\n风力:" + detail.getProperty(19).toString() + "\n"; iconAfterday[0] = parseIcon(detail.getProperty(20).toString()); iconAfterday[1] = parseIcon(detail.getProperty(21).toString()); // 更新当天的天气实况 textWeatherCurrent.setText(weatherCurrent); // 更新显示今天天气的图标和文本框 textWeatherToday.setText(weatherToday); todayWhIcon1.setImageResource(iconToday[0]); todayWhIcon2.setImageResource(iconToday[1]); // 更新显示明天天气的图标和文本框 textWeatherTomorrow.setText(weatherTomorrow); tomorrowWhIcon1.setImageResource(iconTomorrow[0]); tomorrowWhIcon2.setImageResource(iconTomorrow[1]); // 更新显示后天天气的图标和文本框 textWeatherAfterday.setText(weatherAfterday); afterdayWhIcon1.setImageResource(iconAfterday[0]); afterdayWhIcon2.setImageResource(iconAfterday[1]); } // 工具方法,该方法负责把返回的天气图标字符串,转换为程序的图片资源ID。 private int parseIcon(String strIcon) { if (strIcon == null) return -1; if ("0.gif".equals(strIcon)) return R.drawable.a_0; if ("1.gif".equals(strIcon)) return R.drawable.a_1; if ("2.gif".equals(strIcon)) return R.drawable.a_2; if ("3.gif".equals(strIcon)) return R.drawable.a_3; if ("4.gif".equals(strIcon)) return R.drawable.a_4; if ("5.gif".equals(strIcon)) return R.drawable.a_5; if ("6.gif".equals(strIcon)) return R.drawable.a_6; if ("7.gif".equals(strIcon)) return R.drawable.a_7; if ("8.gif".equals(strIcon)) return R.drawable.a_8; if ("9.gif".equals(strIcon)) return R.drawable.a_9; if ("10.gif".equals(strIcon)) return R.drawable.a_10; if ("11.gif".equals(strIcon)) return R.drawable.a_11; if ("12.gif".equals(strIcon)) return R.drawable.a_12; if ("13.gif".equals(strIcon)) return R.drawable.a_13; if ("14.gif".equals(strIcon)) return R.drawable.a_14; if ("15.gif".equals(strIcon)) return R.drawable.a_15; if ("16.gif".equals(strIcon)) return R.drawable.a_16; if ("17.gif".equals(strIcon)) return R.drawable.a_17; if ("18.gif".equals(strIcon)) return R.drawable.a_18; if ("19.gif".equals(strIcon)) return R.drawable.a_19; if ("20.gif".equals(strIcon)) return R.drawable.a_20; if ("21.gif".equals(strIcon)) return R.drawable.a_21; if ("22.gif".equals(strIcon)) return R.drawable.a_22; if ("23.gif".equals(strIcon)) return R.drawable.a_23; if ("24.gif".equals(strIcon)) return R.drawable.a_24; if ("25.gif".equals(strIcon)) return R.drawable.a_25; if ("26.gif".equals(strIcon)) return R.drawable.a_26; if ("27.gif".equals(strIcon)) return R.drawable.a_27; if ("28.gif".equals(strIcon)) return R.drawable.a_28; if ("29.gif".equals(strIcon)) return R.drawable.a_29; if ("30.gif".equals(strIcon)) return R.drawable.a_30; if ("31.gif".equals(strIcon)) return R.drawable.a_31; return 0; } }上面的Activity代码只是简单的调用Web Service操作,解析Web Service返回的SOAP消息包,并把SOAP消息包中的数据显示出来。
注意,android sdk 4.0版本不能运行,目前也不知道原因。低于4.0版本的可以
下载Demo代码点击此处
http://download.csdn.net/detail/wtyvhreal/8168417