Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android開發之使用Web Service進行網絡編程

Android開發之使用Web Service進行網絡編程

編輯:關於Android編程

使用Web Service進行網絡編程

Android應用通常都是運行在手機平台上,手機系統的硬件資源是有限的,不管是存儲能力還是計算能力都有限,在Android系統上開發、運行一些單用戶、小型應用是可能的,

但對於需要進行大量的數據處理、復雜計算的應用,還是只能部署在遠程服務器上,Android 應用將只是充當這些應用的客戶端。

為了讓Android應用與遠程服務器之間進行交互,可以借助子Java的RMI技術,但這要求遠程服務器程序必須采用Java實現;也可以借助於CORBA技術,但這種技術顯得過於復雜,除此之外,Web Service是一種不錯的選擇。

1.Web Service 平台概述

Web Service平台主要涉及的技術有SOAP(Simple Object Access Protocol,簡單對象訪問協議),WSDL( Web Service Description Language,Web Service 描述語言),UDDI(UniversalDescription, Description and Integration,統一描述、發現和整合協議)。

1.1. SOAP (簡單對象訪問協議)

SOAP (SimpleObject Access Protocol,簡單對象訪問協議)是一種具有擴展性的;XML消息協議。SOAP允許一個應用程序向另一個應用程序發送XML消息,SOAP消息是從SOAP 發送者傳至SOAP接收者的單路消息,任何應用程序均可作為發送者或接收者。SOAP僅定義消息結構和消息處理的協議,與底層的傳輸協議獨立。因此,SOAP協議能通過HTTP, JMS 或SMTP協議傳輸。

SOAP依賴於XML文檔來構建,一條SOAP消息就是一份特定的XML文檔,SOAP消息包合如下三個主要元素:

? 必需的根元素,SOAP消息對應的XML文檔以該元素作為根元素。

? 可選的元素,包含SOAP消息的頭信息。

? 必需的元素,包含所有的調用和響應信息。

就目前的SOAP消息的結構來看,根元素的通常只能包含兩個子元素,第 一個子元素是可選的元素,第二個子元素是必需的元素。

1.2. WSDL(WebService 描述語言)

WSDL (WebService Description Language, Web Service 描述語言) 使用 XML 描述Web Service,包括訪問和使用WebService所必需的信息,定義該Web Service的位置、功能及如何通信等描述信息。

一般來說,只要調用者能夠獲取WebService對應的WSDL,就可以從中了解它所提供的服務及如何調用Web Service。因為一份WSDL文件淸晰地定義了三個方面的內容。

? WHAT部分:用於定義Web Service所提供的操作(或方法),也就是Web Service 能做些什麼。由WSDL中的、和元素定義。

? HOW部分:用於定義如何訪問Web Service,包括數據格式詳情和訪問Web Service操作的必要協議。也就是定義了如何訪問Web Service。

? WHERE部分:用於定義Web Service位於何處,如何使用特定協議決定的網絡地址(如URL)指定。該部分使用元素定義,可在WSDL文件的最後部分看到元素。

一份WSDL文檔通常可分為兩個部分:

? 第一個部分定義了服務接口,它在WSDL中由元素和 兩個元素組成,其中元素定義了操作的交互方式。而 元素裡則可包含任意數量的元素,每個元素代表一個允許遠程調用的操作(即方法)。

? WSDL的第二個部分定義了服務實現,它在WSDL中由元素和 兩個元素組成,其中定義使用特定的通信協議、數據編碼模型和底層通信協議,將Web Service服務接口定義映射到具體實現。而 元素則包含一系列的子元素,< portType.../>子元素將會把綁定機制、服務訪問協議和端點地址結合在一起。

1.3. UDDI(統一描述、發現和整合協議)

UDDI (UniversalDescription, Description and Integration,統一描述、發現和整合協議)是一套信息注冊規范,它具有如下特點:

? 基於Web。

? 分布式。

UDDI包括一組允許企業向外注冊WebService、以使其他企業發現訪問的實現標准。 UDDI的核心組件是UDDI注冊中心,它使用XML文件來描述企業及其提供的Web Service, 通過使用UDDI, Web Service提供者可以對外注冊Web Service,從而允許其他企業來調用該企業注冊的Web Service。Web Service提供者通過UDDI注冊中心的Web界面,將它所供的Web Service的信息加入UDDI注冊中心,該Web Service就可以被發現和調用。

Web Service使用者也通過UDDI注冊中心査找、發現自己所需的服務。當Web Service使用者找到自己所需的服務之後,可以將自己綁定到指定的Web Service提供者,再根據該 Web Service對應的WSDL文檔來調用對方的服務。

2. 使用Android啟用調用Web Service

Java本身提供了豐富的WebService支持,比如Sun公司制定的JAX-WS 2規范,還有 Apache開源組織所提供的Axis1、Axis2、CXF等,這些技術不僅可以用於非常方便地對外提供Web Service,也可以用於簡化Web Service的客戶端編程。

對於手機等小型設備而言,它們的計算資源、存儲資源都十分有限,因此Android應用不大可能需要對外提供Web Service,Android應用通常只是充當Web Service的客戶端,調用遠程Web Serice。

Google為Android平台開發WebService客戶端提供了 ksoap2-android項目,但這個項目並未直接集成在Android平台中,還需要開發人員自行下載。

2.1為Android應用增加ksoap2-android支持的下步驟。

1) 登錄http://code.google.eom/p/ksoap2-android/站點,該站站點有介紹下載ksoap2-androi項目的方法。

2) 下載 ksoap2-android 項目的 ksoap2-android-assembly-3.0.0-RC4.jar-with-dependencies. jar 包。

3) 將下載的jar包放到android項目的libs目錄下即可。

為Android項目添加了ksoap2-android包之後,接下來借助 ksoap2-android項目來調用WebService所暴露出來的操作。

2.2使用ksoap2-android調用Web Service操作的步驟如下:

1) 創建HttpTransportSE對象,該對象用於調用WebService操作。

2) 創建 SoapSerializationEnvelope對象。

提示:從名稱來看SoapSerializationEnvelope代表一個SOAP消息封包;但ksoap2-android 項目對 SoapSerializationEnvelope 的處理比較特殊,它是HttpTransportSE調用WebService時信息的載體;客戶端需要傳入的參數,需要通過SoapSerializationEnvelope對象的bodyOut屬性傳給服務器;服務器響應生成的SOAP消息也通過該對象的body Out屬性來獲取。

3) 創建SoapObject對象,創建該對象時需要傳入所要調用WebService的命名空間、Web Service方法名。

4) 如果有參數需要傳給Web Service服務器端,調用SoapObject對象的addProperty(Stringname,Object value)方法來設置參數,該方法的name參數指定參數名;value參數指定參數值。

5) 調用SoapSerializationEnvelope的setOutputSoapObject()方法,或者直接對bodyOut屬性賦值,將前兩步創逆的SoapObject對象設為SoapSerializationEnvelope的傳出SOAP消息體。

6) 調用對象的call()方法,並以SoapSerializationEnvelope作為參數調用遠程WebService。

7) 調用完成後,訪問SoapSerializationEnvelope對象的bodyln屬性,該屬性返回一個 SoapObject對象,該對象就代表了Web Service的返回消息。解析該SoapObject對象,即可獲取調用Web Service的返回值。

2.3實例:調用Web Service實現天氣預報

在開發天氣預報的Android應用之前,首先需要找到一個可以對外提供天氣預報的Web Service,通過搜索,發現http://webservice.webxml.com.cn/WebServices/WeatherWS.asmx 站點 可以對外提供天氣預報的WebService,因此程序將會調用該站點的Web Service來實現天氣預報。

為了讓應用界面更加美觀,可以訪問http://www.webxml.com.cn/images/weather.zip下載 各種天氣圖標,可以使用這些天氣圖標來美化應用。

本程序主要需要調用如下三個Web Seivice操作:

* 獲取省份。

* 根據省份獲取城市。

* 根據城市獲取天氣。

為了調用上面的三個WebService應用程序提供如下工具類。

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 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> task = new FutureTask>(

new Callable>()

{

@Override

public List 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 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> task = new FutureTask>(

new Callable>()

{

@Override

public List 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 parseProvinceOrCity(SoapObject detail)

{

ArrayList result = new ArrayList();

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;

nbsp; 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 task = new FutureTask(

new Callable()

{

@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;

}

}

上面的程序調用Web Service的方法還是沒有改變,前面兩個方法——獲取系統支持的省 份列表,根據省份獲取城市列表——將遠程Web Service返回的數據解析成List後返回,這樣方便Android應用使用。由於第二個方法需要返回的數據量較多,所以程序直接返回了 SoapObject 對象。

上面的程序中調用WebService時將SoapSerializationEnvelope對象的dotNet屬性設為 true——因為上面這個網站是通過.NET來對外提供WebService的,因此需要將 SoapSerializationEnvelope 對象的 dotNet 屬性設為 true。

有了上面的調用WebService的工具類之後,接下來可以在Activity中使用該工具類來獲取天氣服務信息。該Activity使用了兩個Spinner讓用戶選擇省份、城市,當用戶選擇指定城市後,系統將會加載該程序的天氣信息。

該程序的界面布局代碼如下:

"1.0" encoding="utf-8"?>

"http://schemas.android.com/apk/res/android"

android:orientation="vertical"

android:layout_width="fill_parent"

android:layout_height="wrap_content">

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:orientation="horizontal">

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:hint="@string/province"/>

android:id="@+id/province"

android:layout_width="wrap_content"

android:layout_height="wrap_content"/>

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:hint="@string/city"/>

android:id="@+id/city"

android:layout_width="wrap_content"

android:layout_height="wrap_content"/>

android:id="@+id/weatherCurrent"

android:layout_width="fill_parent"

android:layout_height="wrap_content"/>

android:layout_width="fill_parent"

android:layout_height="wrap_content">

android:id="@+id/todayWhIcon1"

android:layout_width="wrap_content"

android:layout_height="wrap_content"/>

android:id="@+id/todayWhIcon2"

android:layout_width="wrap_content"

android:layout_height="wrap_content"/>

android:id="@+id/weatherToday"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:layout_weight="1"/>

android:layout_width="fill_parent"

android:layout_height="wrap_content">

android:id="@+id/tomorrowWhIcon1"

android:layout_width="wrap_content"

android:layout_height="wrap_content"/>

android:id="@+id/tomorrowWhIcon2"

android:layout_width="wrap_content"

android:layout_height="wrap_content"/>

android:id="@+id/weatherTomorrow"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:layout_weight="1"/>

android:layout_width="fill_parent"

android:layout_height="wrap_content">

android:id="@+id/afterdayWhIcon1"

android:layout_width="wrap_content"

android:layout_height="wrap_content"/>

android:id="@+id/afterdayWhIcon2"

android:layout_width="wrap_content"

android:layout_height="wrap_content"/>

android:id="@+id/weatherAfterday"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:layout_weight="1"/>

當程序加載時,程序會調用WebServiceUtil的getProvinceList()方法來獲取省份列表,並 使用第一個Spinner加載、顯示所有省份:當用戶改變選擇了省份之後,程序會調用 WebServiceUtil的getCityListByProvince(Stringprovince)方法來獲取該省份的全部城市:當用 戶改變選擇城市之後,程序會調用WebServiceUtil的getWeatherByCity(StringcityName)方法 獲取該城市的天氣。

該Activity的代碼如下:

public class GetWeather 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 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 cities = WebServiceUtil

.getCityListByProvince(provinceSpinner.getSelectedItem()

.toString());

ListAdapter cityAdapter = new ListAdapter(GetWeather.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代碼己經不再涉及調用WebService的代碼了,只是簡單地調用Web Service操作,解析Web Service返回的SOAP消息包,並把SOAP消息包中的數據顯示出來。

未完待續..........

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved