Android學習--WebService初步

 根據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通過調用Webservice實現天氣預報

在開發天氣預報的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,那麼天氣預報的功能自然也就失效啦

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章