1. 程式人生 > >在Android 中使用KSOAP2調用WebService(轉)

在Android 中使用KSOAP2調用WebService(轉)

arch 輸出 移植 發包 runnable round csdn service服務 語言

  WebService 是一種基於SOAP協議的遠程調用標準。通過WebService可以將不同操作系統平臺,不同語言、不同技術整合到一起。在Android SDK中並沒有提供調用WebService的庫,因此,需要使用第三方類庫(KSOAP2)來調用WebService。在本文將介紹在Android 中調用WebService的具體細節,並在最後給出一個完整的例子來演示如何使用KSOAP2來調用WebService。

安裝第三方類庫:KSOAP2 PC版本的WebService客戶端類庫非常豐富,例如,Axis2、CXF等,但這些類庫對於Android系統過於龐大,也未必很容易移植到 Android系統上。因此,這些開發包並不在我們考慮的範圍內。適合手機的WebService客戶端類庫也有一些。本例使用了比較常用的 KSOAP2。讀者可以從如下的地址下載Android版的KSOAP2。 http://code.google.com/p/ksoap2-android/downloads/list?can=1&q=&colspec=Filename+Summary+Uploaded+Size+DownloadCount

將下載後的jar文件復制到Eclipse工程的lib目錄中(如果沒有該目錄,可以新建一個,當然,也可以放在其他的目錄中)。並在Eclipse工程中引用這個jar包,引用後的Eclipse工程目錄結構如圖1所示。

圖1 引用KSOAP2開發包 使用KSOAP2調用WebService 讀者可按如下6步來調用WebService的方法。 1. 指定WebService的命名空間和調用的方法名,代碼如下:
SoapObject request = new SoapObject("http://service", "getName");    

SoapObject類的第1個參數表示WebService的命名空間,可以從WSDL文檔中找到WebService的命名空間。第2個參數表示要調用的WebService方法名。

2. 設置調用方法的參數值,這一步是可選的,如果方法沒有參數,可以省略這一步。設置方法的參數值的代碼如下:
request.addProperty("param1", "value1");    

request.addProperty("param2", "value2");    

要註意的是,addProperty方法的第1個參數雖然表示調用方法的參數名,但該參數值並不一定與服務端的WebService類中的方法參數名一致,只要設置參數的順序一致即可。 3. 生成調用WebService方法的SOAP請求信息。該信息由SoapSerializationEnvelope對象描述,代碼如下:
SoapSerializationEnvelope envelope = new
SoapSerializationEnvelope(SoapEnvelope.VER11); envelope.bodyOut = request;

創建SoapSerializationEnvelope對象時需要通過SoapSerializationEnvelope類的構造方法設置SOAP協 議的版本號。該版本號需要根據服務端WebService的版本號設置。在創建SoapSerializationEnvelope對象後,不要忘了設置 SoapSerializationEnvelope類的bodyOut屬性,該屬性的值就是在第1步創建的SoapObject對象。 4. 創建HttpTransportSE對象。通過HttpTransportSE類的構造方法可以指定WebService的WSDL文檔的URL,代碼如下:
1 HttpTransportSE ht =     
2 new HttpTransportSE("http://192.168.17.156:8080/axis2/services/SearchProductService?wsdl");   

5. 使用call方法調用WebService方法,代碼如下:

ht.call(null, envelope);    

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

6. 使用getResponse方法獲得WebService方法的返回結果,代碼如下:
SoapObject soapObject = (SoapObject) envelope.getResponse();    

示例:通過WebService查詢產品信息 本例涉及到一個WebService服務端程序和一個OPhone客戶端程序。讀者可直接將服務端程序(axis2目錄)復制到<Tomcat安裝目錄>\webapps目錄中,然後啟動Tomcat,並在瀏覽器地址欄中輸入如下的URL: http://localhost:8080/axis2 如果在瀏覽器中顯示如圖2所示的頁面,說明服務端程序已經安裝成功。 技術分享 圖2 WebService主頁面 這個服務端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 WSDL文檔 在圖3中的黑框中就是WebService的命名空間,也是SoapObject類的構造方法的第1個參數值。這個WebService程序可以直接使用如下的URL進行測試。 http://localhost:8080/axis2/services/SearchProductService/getProduct?param0=iphone 測試的結果如圖4所示。 技術分享 圖4 測試getProduct方法 從圖4所示的測試結果可以看出,Axis2將getProduct方法返回的Product對象直接轉換成了XML文檔(實際上是SOAP格式)返回。 下面我們來根據前面介紹的使用KSOAP2的步驟來編寫調用WebService的OPhone客戶端程序,代碼如下: 技術分享
 1     package net.blogjava.mobile.wsclient;  
 2        
 3     import org.ksoap2.SoapEnvelope;  
 4     import org.ksoap2.serialization.SoapObject;  
 5     import org.ksoap2.serialization.SoapSerializationEnvelope;  
 6     import org.ksoap2.transport.HttpTransportSE;  
 7     import android.app.Activity;  
 8     import android.os.AsyncTask;  
 9     import android.os.Bundle;  
10     import android.view.View;  
11     import android.view.View.OnClickListener;  
12     import android.widget.Button;  
13     import android.widget.EditText;  
14     import android.widget.TextView;  
15        
16     public class Main extends Activity implements OnClickListener  
17     {  
18         private EditText etProductName;  
19         private TextView tvResult;  
20        
21         class WSAsyncTask extends AsyncTask  
22         {  
23             String result = "";  
24             @Override  
25             protected Object doInBackground(Object... params)  
26             {  
27                 try  
28                 {  
29                     String serviceUrl = "http://192.168.17.156:8080/axis2/services/SearchProductService?wsdl";  
30                     String methodName = "getProduct";  
31                     SoapObject request = new SoapObject("http://service",  
32                             methodName);  
33                     request.addProperty("productName", etProductName.getText().toString());  
34                     SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(  
35                             SoapEnvelope.VER11);  
36                     envelope.bodyOut = request;  
37                     HttpTransportSE ht = new HttpTransportSE(serviceUrl);  
38        
39                     ht.call(null, envelope);  
40                     if (envelope.getResponse() != null)  
41                     {  
42                         SoapObject soapObject = (SoapObject) envelope.getResponse();  
43                         result = "產品名稱:" + soapObject.getProperty("name") + "\n";  
44                         result += "產品數量:" + soapObject.getProperty("productNumber")  
45                                 + "\n";  
46                         result += "產品價格:" + soapObject.getProperty("price");  
47        
48                     }  
49                     else  
50                     {  
51                         result = "無此產品.";  
52                     }  
53                 }  
54                 catch (Exception e)  
55                 {  
56                     result = "調用WebService錯誤.";  
57                 }  
58                 // 必須使用post方法更新UI組件  
59                 tvResult.post(new Runnable()  
60                 {  
61                     @Override  
62                     public void run()  
63                     {  
64                         tvResult.setText(result);  
65        
66                     }  
67                 });  
68                 return null;  
69             }  
70        
71         }  
72         @Override  
73         public void onClick(View view)  
74     {  
75         // 異步執行調用WebService的任務    
76             new WSAsyncTask().execute();  
77         }  
78         @Override  
79         public void onCreate(Bundle savedInstanceState)  
80         {  
81             super.onCreate(savedInstanceState);  
82             setContentView(R.layout.main);  
83             Button btnSearch = (Button) findViewById(R.id.btnSearch);  
84             btnSearch.setOnClickListener(this);  
85             etProductName = (EditText) findViewById(R.id.etProductName);  
86             tvResult = (TextView) findViewById(R.id.tvResult);  
87        
88         }  
89     }  
View Code

在編寫上面代碼時應註意如下兩點:

  • 在 第2步中addProperty方法的第1個參數值是productName,該值雖然是getProduct方法的參數名,但addProperty方 法的第1個參數值並不限於productName,讀者可以將這個參數設為其他的任何字符串(但該值必須在XML中是合法的,例如,不是設為 “<”、“>”等XML預留的字符串)。
  • 通過SoapObject類的getProperty方法可以獲得Product對象的屬性值,這些屬性名就是圖4所示的測試結果中的屬性名。
運行本例,在文本框中輸入“htc hero”,單擊【查詢】按鈕,會在按鈕下方顯示如圖5所示的查詢結果。 技術分享 圖5 顯示查詢結果 防止UI組件阻塞 從功能上看,本文示例中給出的代碼並沒有任何問題。但可能有的讀者會有這樣的擔心:如果調用WebService的用戶很多,至使服務端響應遲緩;或服務 端的IP根本就不對,那麽在這些情況下,用戶界面的按鈕和文本框組件豈不是象“死”了一樣無法響應用戶的其他動作。當然,發生這種情況的可能性是有的,尤 其是在復雜的網絡環境中發生的可能性是很大的,一但發生這種事情,就會使整個軟件系統在用戶體驗上變得非常糟糕。 用戶和開發人員都希望改善這種糟糕的情況。最理想的狀態是單擊按鈕調用WebService方法時,即使由於某種原因,WebService方法並未立即返回,界面上的組件仍然會處於活動狀態,也就是說,用戶仍然可以使用當前界面中的其他組件。 在OPhone中可以采用異步的方式來達到這個目的。異步實際上就是通過多線程的方式來實現。一般使用new Thread(this).start()來創建和開始一個線程。但本節並不使用Thread來實現異步,而是通過AsyncTask類使要執行的任務 (調用WebService)在後臺執行。 下面先看看改進後的代碼。 技術分享
 1     package net.blogjava.mobile.wsclient;  
 2        
 3     import org.ksoap2.SoapEnvelope;  
 4     import org.ksoap2.serialization.SoapObject;  
 5     import org.ksoap2.serialization.SoapSerializationEnvelope;  
 6     import org.ksoap2.transport.HttpTransportSE;  
 7     import android.app.Activity;  
 8     import android.os.AsyncTask;  
 9     import android.os.Bundle;  
10     import android.view.View;  
11     import android.view.View.OnClickListener;  
12     import android.widget.Button;  
13     import android.widget.EditText;  
14     import android.widget.TextView;  
15        
16     public class Main extends Activity implements OnClickListener  
17     {  
18         private EditText etProductName;  
19         private TextView tvResult;  
20        
21         class WSAsyncTask extends AsyncTask  
22         {  
23             String result = "";  
24             @Override  
25             protected Object doInBackground(Object... params)  
26             {  
27                 try  
28                 {  
29                     String serviceUrl = "http://192.168.17.156:8080/axis2/services/SearchProductService?wsdl";  
30                     String methodName = "getProduct";  
31                     SoapObject request = new SoapObject("http://service",  
32                             methodName);  
33                     request.addProperty("productName", etProductName.getText().toString());  
34                     SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(  
35                             SoapEnvelope.VER11);  
36                     envelope.bodyOut = request;  
37                     HttpTransportSE ht = new HttpTransportSE(serviceUrl);  
38        
39                     ht.call(null, envelope);  
40                     if (envelope.getResponse() != null)  
41                     {  
42                         SoapObject soapObject = (SoapObject) envelope.getResponse();  
43                         result = "產品名稱:" + soapObject.getProperty("name") + "\n";  
44                         result += "產品數量:" + soapObject.getProperty("productNumber")  
45                                 + "\n";  
46                         result += "產品價格:" + soapObject.getProperty("price");  
47        
48                     }  
49                     else  
50                     {  
51                         result = "無此產品.";  
52                     }  
53                 }  
54                 catch (Exception e)  
55                 {  
56                     result = "調用WebService錯誤.";  
57                 }  
58                 // 必須使用post方法更新UI組件  
59                 tvResult.post(new Runnable()  
60                 {  
61                     @Override  
62                     public void run()  
63                     {  
64                         tvResult.setText(result);  
65        
66                     }  
67                 });  
68                 return null;  
69             }  
70        
71         }  
72         @Override  
73         public void onClick(View view)  
74     {  
75         // 異步執行調用WebService的任務    
76             new WSAsyncTask().execute();  
77         }  
78         @Override  
79         public void onCreate(Bundle savedInstanceState)  
80         {  
81             super.onCreate(savedInstanceState);  
82             setContentView(R.layout.main);  
83             Button btnSearch = (Button) findViewById(R.id.btnSearch);  
84             btnSearch.setOnClickListener(this);  
85             etProductName = (EditText) findViewById(R.id.etProductName);  
86             tvResult = (TextView) findViewById(R.id.tvResult);  
87        
88         }  
89     }  
View Code

調用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組件中輸出相應的返回值。 總結 本文主要介紹了如何使用KSOAP2來調用WebService。KSOAP2是第三方開發的專門用於在移動設備調用WebService的類庫。使用 KSOAP2調用WebService可分為6步來完成,其中主要使用了SoapObject對象來指定了要調用的方法,然後通過 HttpTransportSE對象的call方法來調用WebService的方法,最後通過getResponse方法返回結果。讀者可以通過本文提 供的完整示例來體會使用KSOAP2調用WebService的完整過程。在最後還介紹了如何通過異步調用WebService的方式來防止因服務端故障 或其他原因導致的UI組件阻塞。 本文出自:http://blog.csdn.net/sinat_29255093/article/details/51817918

在Android 中使用KSOAP2調用WebService(轉)