通过这一篇文章WebService的读书笔记对Web Service的认识,现在来写一个小应用Android通过调用Webservice实现天气预报来加强对Web Srevice的学习
在开发天气预报的Android应用之前,首先需要找到一个可以对外提供天气预报的Web Service,通过搜索发现站点http://webservice.webxml.com.cn/WebServices/WeatherWS.asmx可以对外提供天气预报的Web Service,因此程序会调用此站点的Web Service来实现天气预报。(注意:如果该站点的天气预报Web Service服务已经停止,那么本程序将无法正常调用Web Service,那么天气预报的功能自然也就失效啦)
好啦,现在开始step by step地实现该应用程序。
step1:新建Android项目MyWeather
step2:获取并使用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
选择我们的项目,右键菜单中 Build Path –> Add External Archives… 增加这个下载的包
step3:设计应用的UI界面 /res/layout/main.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="wrap_content"> <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>
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">天气预报</string> <string name="btn_apply">查询</string> <string name="text_hint">城市中文名</string> <string name="province">省份</string> <string name="city">城市</string> </resources>
step3:编写调用Web Service的工具类 cn.roco.weather.WebServiceUtil.java
因为本程序主要需要调用如下三个Web Service操作:
a.获取省份:getRegionProvince方法
b.根据省份获取城市:getSupportCityString方法
c.根据城市获取天气:getWeather方法
为了让应用界面更加美观,可以访问http://www.webxml.com.cn/images/weather.zip下载各种天气图标,可以使用这些天气图标来美化应用。
package cn.roco.weather; import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.ksoap2.SoapEnvelope; import org.ksoap2.serialization.SoapObject; import org.ksoap2.serialization.SoapSerializationEnvelope; import org.ksoap2.transport.HttpTransportSE; import org.xmlpull.v1.XmlPullParserException; 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() { /** * 调用远程Web Service的getRegionProvince方法: 获得中国省份、直辖市、地区和与之对应的ID * <ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://WebXml.com.cn/"> <string>黑龙江,3113</string> <string>吉林,3114</string> <string>辽宁,3115</string> <string>内蒙古,3116</string> <string>河北,3117</string> <string>河南,3118</string> <string>山东,3119</string> <string>山西,31110</string> <string>江苏,31111</string> <string>安徽,31112</string> <string>陕西,31113</string> <string>宁夏,31114</string> <string>甘肃,31115</string> <string>青海,31116</string> <string>湖北,31117</string> <string>湖南,31118</string> <string>浙江,31119</string> <string>江西,31120</string> <string>福建,31121</string> <string>贵州,31122</string> <string>四川,31123</string> <string>广东,31124</string> <string>广西,31125</string> <string>云南,31126</string> <string>海南,31127</string> <string>新疆,31128</string> <string>西藏,31129</string> <string>台湾,31130</string> <string>北京,311101</string> <string>上海,311102</string> <string>天津,311103</string> <string>重庆,311104</string> <string>香港,311201</string> <string>澳门,311202</string> <string>钓鱼岛,311203</string> </ArrayOfString> */ String methodName = "getRegionProvince"; //获得中国省份、直辖市、地区和与之对应的ID // 创建HttpTransportSE传输对象,该对象用于调用Web Service操作 HttpTransportSE ht = new HttpTransportSE(SERVICE_URL); ht.debug = true; // 使用SOAP1.1协议创建Envelop对象 SoapSerializationEnvelope envelope = new SoapSerializationEnvelope( SoapEnvelope.VER11); // 实例化SoapObject对象,传入所要调用的Web Service的命名空间,Web Service方法名 SoapObject soapObject = new SoapObject(SERVICE_NS, methodName); //将 soapObject对象设置为SoapSerializationEnvelope对象的传出SOAP消息 envelope.bodyOut = soapObject; /** * 因为什么这个网站是通过.NET对外提供Web Service的, * 因此设置与.Net提供的Web Service保持较好的兼容性 */ envelope.dotNet = true; try { // 调用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); } } catch (IOException e) { e.printStackTrace(); } catch (XmlPullParserException e) { e.printStackTrace(); } return null; } // 根据省份获取城市列表 public static List<String> getCityListByProvince(String province) { /** * 调用的方法 * 获得支持的城市/地区名称和与之对应的ID 输入参数:theRegionCode = 省市、国家ID或名称,返回数据:一维字符串数组。 如:输入北京的theRegionCode:311101得到的返回结果为: <ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://WebXml.com.cn/"> <string>北京,792</string> <string>昌平,785</string> <string>大兴,826</string> <string>房山,827</string> <string>怀柔,752</string> <string>门头沟,788</string> <string>密云,751</string> <string>平谷,756</string> <string>顺义,741</string> <string>通州,3409</string> <string>延庆,746</string> <string>海淀,742</string> <string>朝阳,3408</string> <string>丰台,795</string> <string>石景山,794</string> </ArrayOfString> */ String methodName = "getSupportCityString"; // 创建HttpTransportSE传输对象 HttpTransportSE ht = new HttpTransportSE(SERVICE_URL); ht.debug = true; // 实例化SoapObject对象 SoapObject soapObject = new SoapObject(SERVICE_NS, methodName); // 添加一个请求参数 soapObject.addProperty("theRegionCode", province); // 使用SOAP1.1协议创建Envelop对象 SoapSerializationEnvelope envelope = new SoapSerializationEnvelope( SoapEnvelope.VER11); envelope.bodyOut = soapObject; // 设置与.Net提供的Web Service保持较好的兼容性 envelope.dotNet = true; try { // 调用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); } } catch (IOException e) { e.printStackTrace(); } catch (XmlPullParserException e) { e.printStackTrace(); } return null; } // 解析服务器响应的SOAP消息。 private static List<String> parseProvinceOrCity(SoapObject detail) { List<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) { /** * 获得天气预报数据 输入参数:城市/地区ID或名称,返回数据:一维字符串数组。 如:输入theCityCode:792(<string>北京,792</string>)得到的返回结果为: This XML file does not appear to have any style information associated with it. The document tree is shown below. <ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://WebXml.com.cn/"> <string>直辖市 北京</string> <string>北京</string> <string>792</string> <string>2013/04/30 03:47:53</string> <string>今日天气实况:气温:14℃;风向/风力:东风 2级;湿度:21%</string> <string>空气质量:良;紫外线强度:强</string> <string> 穿衣指数:建议着薄型套装等春秋过渡装。年老体弱者宜着套装。但昼夜温差较大,注意适当增减衣服。 过敏指数:天气条件极易诱发过敏,易过敏人群尽量减少外出,外出宜穿长衣长裤并佩戴好眼镜和口罩,外出归来时及时清洁手和口鼻。 运动指数:天气较好,但由于风力较大,推荐您在室内进行低强度运动,若在户外运动请注意避风。 洗车指数:适宜洗车,未来持续两天无雨天气较好,适合擦洗汽车,蓝天白云、风和日丽将伴您的车子连日洁净。 晾晒指数:天气不错,适宜晾晒。赶紧把久未见阳光的衣物搬出来吸收一下太阳的味道吧! 旅游指数:天气较好,风稍大,但温度适宜,是个好天气哦。很适宜旅游,您可以尽情地享受大自然的无限风光。 路况指数:天气较好,路面比较干燥,路况较好。 舒适度指数:白天天气晴好,您在这种天气条件下,会感觉早晚凉爽、舒适,午后偏热。 空气污染指数:气象条件有利于空气污染物稀释、扩散和清除,可在室外正常活动。 紫外线指数:紫外线辐射强,建议涂擦SPF20左右、PA++的防晒护肤品。避免在10点至14点暴露于日光下。 </string> <string>4月30日 晴</string> <string>11℃/27℃</string> <string>北风3-4级转无持续风向微风</string> <string>0.gif</string> <string>0.gif</string> <string>5月1日 晴转多云</string> <string>12℃/25℃</string> <string>无持续风向微风</string> <string>0.gif</string> <string>1.gif</string> <string>5月2日 多云转晴</string> <string>13℃/26℃</string> <string>无持续风向微风</string> <string>1.gif</string> <string>0.gif</string> <string>5月3日 多云转阴</string> <string>11℃/23℃</string> <string>无持续风向微风</string> <string>1.gif</string> <string>2.gif</string> <string>5月4日 阴转多云</string> <string>14℃/27℃</string> <string>无持续风向微风</string> <string>2.gif</string> <string>1.gif</string> </ArrayOfString> */ String methodName = "getWeather"; HttpTransportSE ht = new HttpTransportSE(SERVICE_URL); ht.debug = true; 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; try { ht.call(SERVICE_NS + methodName, envelope); SoapObject result = (SoapObject) envelope.bodyIn; SoapObject detail = (SoapObject) result.getProperty(methodName + "Result"); return detail; } catch (Exception e) { e.printStackTrace(); } return null; } }
step4:编写适配器,用于显示数据 cn.roco.weather.ListAdapter.java
package cn.roco.weather; import java.util.List; import android.content.Context; import android.graphics.Color; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.TextView; public class ListAdapter extends BaseAdapter { private Context context; private List<String> values; public ListAdapter(Context context , List<String> values) { this.context = context; this.values = values; } @Override public int getCount() { return values.size(); } @Override public Object getItem(int position) { return values.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { TextView text = new TextView(context); text.setText(values.get(position)); text.setTextSize(20); text.setTextColor(Color.BLACK); return text; } }
step5:程序的主应用cn.roco.weather.MyWeather.java
package cn.roco.weather; import java.util.List; 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; } }
step6:AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="cn.roco.weather"> <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name=".MyWeather" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> <uses-permission android:name="android.permission.INTERNET"/> </manifest>
step7:部署应用,观看运行效果
==================================下面看一个gif动画===========================================
附注:本应用的源码在:http://pan.baidu.com/share/link?shareid=419671&uk=805959799
关于Web Service的应用还可以查看Android通过调用Webservice实现手机号码归属地查询进行学习
==================================================================================================
作者:欧阳鹏 欢迎转载,与人分享是进步的源泉!
转载请保留原文地址:http://blog.csdn.net/ouyang_peng
==================================================================================================