android基礎知識10:webservice 01:KSOAP2

來源:互聯網
上載者:User

          本文主要介紹android用戶端如何使用webservice。第一篇介紹ksoap2,第二篇介紹rest。

          android基礎知識10:webservice 01:KSOAP2

           android基礎知識10:webservice 02:REST

1、webservice概述

       本部分內容來源於《http://www.w3school.com.cn/webservices/index.asp》

1.1 什麼是Web Services?

  • Web Services 是應用程式組件
  • Web Services 使用開放協議進行通訊
  • Web Services 是獨立的(self-contained)並可自我描述
  • Web Services 可通過使用UDDI來發現
  • Web Services 可被其他應用程式使用
  • XML 是 Web Services 的基礎

1.2 它如何工作?

  • 基礎的 Web Services 平台是 XML + HTTP。
  • HTTP 協議是最常用的網際網路協議。
  • XML 提供了一種可用於不同的平台和程式設計語言之間的語言。
  • Web services 平台的元素:
  • SOAP (簡易對象訪問協議)
  • UDDI (通用描述、發現及整合)
  • WSDL (Web services 描述語言)

1.3 Web services 有兩種類型的應用

  • 可重複使用的應用程式組件

有一些功能是不同的應用程式常常會用到的。那麼為什麼要周而復始地開發它們呢?
Web services 可以把應用程式組件作為服務來提供,比如匯率轉換、天氣預報或者甚至是語言翻譯等等。
比較理想的情況是,每種應用程式組件只有一個最優秀的版本,這樣任何人都可以在其應用程式中使用它。

  • 串連現有的軟體

通過為不同的應用程式提供一種連結其資料的途徑,Web services有助於解決協同工作的問題。
通過使用 Web services,您可以在不同的應用程式與平台之間來交換資料。

1.4 實現手段

        WebService一般分為.Net版和Java版,今天我們主要來實現Java版的WebService,.Net版本的還是比較簡單的。  什麼是WebServices?
       它是一種構建應用程式的普遍模型,可以在任何支援網路通訊的作業系統中實施運行;它是一種新的web應用程式分支,是自包含、自描述、模組化的應用,發行就緒、定位、通過web調用。Web Service是一個應用組件,它邏輯性的為其他應用程式提供資料與服務.各應用程式通過網路通訊協定和規定的一些標準資料格式(Http,XML,Soap)來訪問Web Service,通過Web Service內部執行得到所需結果.Web Service可以執行從簡單的請求到複雜商務處理的任何功能。一旦部署以後,其他Web Service應用程式可以發現並調用它部署的服務。
 關鍵的技術和規則
         在構建和使用Web Service時,主要用到以下幾個關鍵的技術和規則:
  1.XML:描述資料的標準方法.
  2.SOAP:表示資訊交換的協議.
  3.WSDL:Web服務描述語言.
  4.UDDI:通用描述、發現與整合,它是一種獨立於平台的,基於XML語言的用於在互連網上描述商務的協議。

  • XML

   可擴充的標記語言(XML)是Web service平台中表示資料的基本格式。除了易於建立和易於分析外,XML主要的優點在於它既是平台無關的,又是廠商無關的。無關性是比技術優越性更重要的:軟體廠商是不會選擇一個由競爭者所發明的技術的。

  • SOAP

  SOAP是web service的標準通訊協定,SOAP為simple object access protocoll的縮寫,簡易物件存取通訊協定 (SOAP). 它是一種標準化的傳輸訊息的XML訊息格式。

  • WSDL

   WSDL的全稱是web service Description Language,是一種基於XML格式的關於web服務的描述語言。其主要目的在於web service的提供者將自己的web服務的所有相關內容,如所提供的服務的傳輸方式,服務方法介面,介面參數,服務路徑等,產生相應的完全文檔,發布給使用者。使用者可以通過這個WSDL文檔,建立相應的SOAP請求訊息,通過HTTP傳遞給webservice提供者;web服務在完成服務要求後,將SOAP返回訊息傳回要求者,服務要求者再根據WSDL文檔將SOAP返回訊息解析成自己能夠理解的內容。

  • UDDI

   將web service進行UDDI註冊發布,UDDI是一種建立註冊表格服務的規範,以便大家將自己的web service進行註冊發布供使用者尋找.然而當服務提供者想將自己的web service向全世界公布,以便外部找到其服務時,那麼服務提供者可以將自己的web service註冊到相應的UDDI商用註冊網站,目前全球有IBM等4家UDDI商用註冊網站。因為WSDL檔案中已經給定了web service的地址URI,外部可以直接通過WSDL提供的URI進行相應的web service調用。所以UDDI並不是一個必需的web
service組件,服務方完全可以不進行UDDI的註冊。

2、android端webservice的使用

       本文僅介紹如何從android手機端使用webservice。

      目前比較通用的webservice為ksoap2和rest。下面來分別介紹。
3、使用KSOAP2調用WebService

3.1 擷取並使用KSOAP包
         我們在PC機器java用戶端中,需要一些庫,比如XFire,Axis2,CXF等等來支援訪問WebService,但是這些庫並不適合我們資源有限的android手機用戶端,做過JAVA ME的人都知道有KSOAP這個第三方的類庫,可以協助我們擷取伺服器端webService調用,當然KSOAP已經提供了基於android版本的jar包了,那麼我們就開始吧:
       首先下載KSOAP包:ksoap2-android-assembly-2.5.2-jar-with-dependencies.jar包
        然後建立android項目:並把下載的KSOAP包放在android項目的lib目錄下:右鍵->build path->configure build path--選擇Libraries,

以下分為七個步驟來調用WebService方法:

第一:執行個體化SoapObject 對象,指定webService的命名空間(從相關WSDL文檔中可以查看命名空間),以及調用方法名稱。如:

//命名空間    private static final String serviceNameSpace="http://WebXml.com.cn/";    //調用方法(獲得支援的城市)    private static final String getSupportCity="getSupportCity";//執行個體化SoapObject對象        SoapObject request=new SoapObject(serviceNameSpace, getSupportCity);

第二步:假設方法有參數的話,設定調用方法參數,這一步是可選的,如果方法沒有參數,可以省略這一步。
request.addProperty("參數名稱","參數值");

        要注意的是,addProperty方法的第1個參數雖然表示調用方法的參數名,但該參數值並不一定與服務端的WebService類中的方法參數名一致,只要設定參數的順序一致即可。
第三步:設定SOAP請求資訊(參數部分為SOAP協議版本號碼,與你要調用的webService中版本號碼一致):

//獲得序列化的Envelope        SoapSerializationEnvelope envelope=new SoapSerializationEnvelope(SoapEnvelope.VER11);        envelope.bodyOut=request;

       建立SoapSerializationEnvelope對象時需要通過SoapSerializationEnvelope類的構造方法設定SOAP協議的版本號碼。該版本號碼需要根據服務端WebService的版本號碼設定。在建立SoapSerializationEnvelope對象後,不要忘了設定SoapSerializationEnvelope類的bodyOut屬性,該屬性的值就是在第1步建立的SoapObject對象。

第四步:註冊Envelope,
(new MarshalBase64()).register(envelope);
第五步:構建傳輸對象,並指明WSDL文檔URL:

//請求URL    private static final String serviceURL="http://www.webxml.com.cn/webservices/weatherwebservice.asmx";//Android傳輸對象        AndroidHttpTransport transport=new AndroidHttpTransport(serviceURL);        transport.debug=true;

第六步:調用WebService(其中參數為1:命名空間+方法名稱,2:Envelope對象):

transport.call(serviceNameSpace+getWeatherbyCityName, envelope);

        call方法的第1個參數一般為null,第2個參數就是在第3步建立的SoapSerializationEnvelope對象。

第七步:解析返回資料:

if(envelope.getResponse()!=null){                return parse(envelope.bodyIn.toString());            }/**************     * 解析XML     * @param str     * @return     */    private static List<String> parse(String str){        String temp;        List<String> list=new ArrayList<String>();        if(str!=null && str.length()>0){            int start=str.indexOf("string");            int end=str.lastIndexOf(";");            temp=str.substring(start, end-3);            String []test=temp.split(";");                         for(int i=0;i<test.length;i++){                 if(i==0){                     temp=test[i].substring(7);                 }else{                     temp=test[i].substring(8);                 }                 int index=temp.indexOf(",");                 list.add(temp.substring(0, index));             }        }        return list;    }

這樣就成功啦。

3.2 樣本:通過WebService查詢產品資訊
    本例涉及到一個WebService服務端程式和一個OPhone用戶端程式。讀者可直接將服務端程式(axis2目錄)複製到<Tomcat安裝目錄>\webapps目錄中,然後啟動Tomcat,並在瀏覽器地址欄中輸入如下的URL:

http://localhost:8080/axis2

    如果在瀏覽器中顯示2所示的頁面,說明服務端程式已經安裝成功。

   

     這個服務端WebService程式是SearchProductService,實際上SearchProductService是一個Java類,只是利用Axis2將其映射成WebService。在該類中有一個getProduct方法。這個方法有一個String類型的參數,表示產品名稱。該方法返回一個Product對象,該對象有3個屬性:name、price和productNumber。讀者可以使用如下的URL來查看SearchProductService的WSDL文檔。

http://localhost:8080/axis2/services/SearchProductService?wsdl

    顯示WSDL文檔的頁面3所示。

        在圖3中的黑框中就是WebService的命名空間,也是SoapObject類的構造方法的第1個參數值。這個WebService程式可以直接使用如下的URL進行測試。

http://localhost:8080/axis2/services/SearchProductService/getProduct?param0=iphone

        測試的結果4所示。

       從所示的測試結果可以看出,Axis2將getProduct方法返回的Product對象直接轉換成了XML文檔(實際上是SOAP格式)返回。
       下面我們來根據前面介紹的使用KSOAP2的步驟來編寫調用WebService的OPhone用戶端程式,代碼如下:

package net.blogjava.mobile.wsclient; import org.ksoap2.SoapEnvelope;import org.ksoap2.serialization.SoapObject;import org.ksoap2.serialization.SoapSerializationEnvelope;import org.ksoap2.transport.HttpTransportSE;import android.app.Activity;import android.os.Bundle;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.EditText;import android.widget.TextView; public class Main extends Activity implements OnClickListener{    @Override    public void onClick(View view)    {        EditText etProductName = (EditText)findViewById(R.id.etProductName);        TextView tvResult = (TextView)findViewById(R.id.tvResult);        // WSDL文檔的URL,192.168.17.156為PC的ID地址        String serviceUrl = "http://192.168.17.156:8080/axis2/services/SearchProductService?wsdl";        // 定義調用的WebService方法名        String methodName = "getProduct";        // 第1步:建立SoapObject對象,並指定WebService的命名空間和調用的方法名        SoapObject request = new SoapObject("http://service", methodName);        // 第2步:設定WebService方法的參數        request.addProperty("productName", etProductName.getText().toString());        // 第3步:建立SoapSerializationEnvelope對象,並指定WebService的版本        SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);        // 設定bodyOut屬性        envelope.bodyOut = request;        // 第4步:建立HttpTransportSE對象,並指定WSDL文檔的URL        HttpTransportSE ht = new HttpTransportSE(serviceUrl);                try        {             // 第5步:調用WebService            ht.call(null, envelope);            if (envelope.getResponse() != null)            {                // 第6步:使用getResponse方法獲得WebService方法的返回結果                SoapObject soapObject = (SoapObject) envelope.getResponse();                // 通過getProperty方法獲得Product對象的屬性值                String result = "產品名稱:" + soapObject.getProperty("name") + "\n";                result += "產品數量:" + soapObject.getProperty("productNumber") + "\n";                result += "產品價格:" + soapObject.getProperty("price");                tvResult.setText(result);             }            else {                tvResult.setText("無此產品.");            }        }        catch (Exception e)        {        }    }    @Override    public void onCreate(Bundle savedInstanceState)    {        super.onCreate(savedInstanceState);        setContentView(R.layout.main);        Button btnSearch = (Button) findViewById(R.id.btnSearch);        btnSearch.setOnClickListener(this);    }}

        在編寫上面代碼時應注意如下兩點:
        1)在第2步中addProperty方法的第1個參數值是productName,該值雖然是getProduct方法的參數名,但addProperty方法的第1個參數值並不限於productName,讀者可以將這個參數設為其他的任何字串(但該值必須在XML中是合法的,例如,不是設為“<”、“>”等XML預留的字串)。
        2)通過SoapObject類的getProperty方法可以獲得Product對象的屬性值,這些屬性名稱就是圖4所示的測試結果中的屬性名稱。
        運行本例,在文字框中輸入“htc hero”,單擊【查詢】按鈕,會在按鈕下方顯示5所示的查詢結果。

防止UI組件阻塞
        從功能上看,本文樣本中給出的代碼並沒有任何問題。但可能有的讀者會有這樣的擔心:如果調用WebService的使用者很多,至使服務端響應遲緩;或服務端的IP根本就不對,那麼在這些情況下,使用者介面的按鈕和文字框組件豈不是象“死”了一樣無法響應使用者的其他動作。當然,發生這種情況的可能性是有的,尤其是在複雜的網路環境中發生的可能性是很大的,一但發生這種事情,就會使整個軟體系統在使用者體驗上變得非常糟糕。
使用者和開發人員都希望改善這種糟糕的情況。最理想的狀態是單擊按鈕調用WebService方法時,即使由於某種原因,WebService方法並未立即返回,介面上的組件仍然會處於活動狀態,也就是說,使用者仍然可以使用當前介面中的其他組件。
         在OPhone中可以採用非同步方式來達到這個目的。非同步實際上就是通過多線程的方式來實現。一般使用new Thread(this).start()來建立和開始一個線程。但本節並不使用Thread來實現非同步,而是通過AsyncTask類使要執行的任務(調用WebService)在後台執行。
        下面先看看改進後的代碼。

package net.blogjava.mobile.wsclient; import org.ksoap2.SoapEnvelope;import org.ksoap2.serialization.SoapObject;import org.ksoap2.serialization.SoapSerializationEnvelope;import org.ksoap2.transport.HttpTransportSE;import android.app.Activity;import android.os.AsyncTask;import android.os.Bundle;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.EditText;import android.widget.TextView; public class Main extends Activity implements OnClickListener{    private EditText etProductName;    private TextView tvResult;     class WSAsyncTask extends AsyncTask    {        String result = "";        @Override        protected Object doInBackground(Object... params)        {            try            {                String serviceUrl = "http://192.168.17.156:8080/axis2/services/SearchProductService?wsdl";                String methodName = "getProduct";                SoapObject request = new SoapObject("http://service",                        methodName);                request.addProperty("productName", etProductName.getText().toString());                SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(                        SoapEnvelope.VER11);                envelope.bodyOut = request;                HttpTransportSE ht = new HttpTransportSE(serviceUrl);                 ht.call(null, envelope);                if (envelope.getResponse() != null)                {                    SoapObject soapObject = (SoapObject) envelope.getResponse();                    result = "產品名稱:" + soapObject.getProperty("name") + "\n";                    result += "產品數量:" + soapObject.getProperty("productNumber")                            + "\n";                    result += "產品價格:" + soapObject.getProperty("price");                 }                else                {                    result = "無此產品.";                }            }            catch (Exception e)            {                result = "調用WebService錯誤.";            }            // 必須使用post方法更新UI組件            tvResult.post(new Runnable()            {                @Override                public void run()                {                    tvResult.setText(result);                 }            });            return null;        }     }    @Override    public void onClick(View view){    // 非同步執行調用WebService的任務          new WSAsyncTask().execute();    }    @Override    public void onCreate(Bundle savedInstanceState)    {        super.onCreate(savedInstanceState);        setContentView(R.layout.main);        Button btnSearch = (Button) findViewById(R.id.btnSearch);        btnSearch.setOnClickListener(this);        etProductName = (EditText) findViewById(R.id.etProductName);        tvResult = (TextView) findViewById(R.id.tvResult);     }}

        調用WebService的核心代碼與樣本中的代碼完全一樣,在這裡就不再做具體的介紹了。但在編寫上面的代碼時還需要注意如下幾點。
       1. 一般需要編寫一個AsyncTask的子類來完成後台執行任務的工作。
        2.  AsyncTask的核心方法是doInBackground,當調用AsyncTask類的execute方法時,doInBackground方法會非同步執行。因此,可以將執行任務的代碼寫在doInBackground方法中。
        3. 由於本例中的TextView組件是在主線程(UI線程)中建立的,因此,在其他的線程(doInBackground方法所在的線程)中不能直接更新TextVew組件。為了更新TextView組件,需要使用TextView類的post方法。該方法的參數是一個Runnable對象,需要將更新TextView組件的代碼寫在Runnable介面的run方法中。
        4. 雖然不能在其他線程中更新UI組件,但可以從其他線程直接讀取UI組件的值。例如,在doInBackground方法中直接讀取了EditText組件的值。
        5. 調用AsyncTask類的execute方法後會立即返回。execute方法的參數就是doInBackground方法的參數。doInBackground方法的傳回值可以通過AsyncTask.execute(...).get()方法獲得。

       讀者可以將本例中的IP改成其他的值,看看單擊按鈕後,是否還可在文字框中輸入其他的內容。如果這個IP是正確的,並且WebService可訪問,那麼會在TextView組件中輸出相應的傳回值。

參考文獻:

http://www.w3school.com.cn

在OPhone 中使用KSOAP2調用WebService

Android開發WebService(Java版)

Android與伺服器端資料互動(基於SOAP協議整合android+webservice)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.