Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android通過ksoap2這個框架調用webservice大講堂

Android通過ksoap2這個框架調用webservice大講堂

編輯:關於Android編程

昨天有人問我Android怎麼連接mysql數據庫,和對數據庫的操作呀,我想把,給他說說json通信,可是他並不知道怎麼弄,哎算了吧,直接叫他用ksoap吧,給他說了大半天,好多零碎的知識,看來還是有必要把這些東西整合起來,一方面自己有時候也看,另一方面當然是能幫助沒有做個的小伙伴,其實東西不是很多,就是講的有點詳細,不怕多,就怕不仔細,
WebServices簡介
Web services是一種部署在Web上的對象或者組件,能夠通過Internet進行調用的應用程序。Web services 建立在以XML為主的開放的web規范技術基礎上,其業務邏輯對調用者來說是透明的。

Webservices調用需要注意的問題(附案例)
接下來我們結合一個案例來理解整個調用過程,針對當時開發時遇到的問題,進行詳細說明。
附:表達能力有限,有很多東西講的不是很清楚,請結合附帶案例看此文檔,希望能幫到你
准備工作
相關jar包導入
新建android項目,將ksoap2-android-assembly-3.0.0-jar-with-dependencies.jar放在android項目的lib目錄下,檢查jar包是否如下圖所示:
這裡寫圖片描述
相關權限添加
既然是訪問網絡操作,就需要添加訪問網絡的權限:
對AndroidManifest.xml文件進行修改,添加網絡權限
這裡寫圖片描述
調用webService服務步驟
第一步,指定WebServices的命名空間和調用的方法名
SoapObjectrpc = new SoapObject(NameSpace,methodName);
第二步,設置需要調用的webServices接口需要傳入的參數
rpc.addPrZ喎?/kf/ware/vc/" target="_blank" class="keylink">vcGVydHkocHJvUGVydHlOYW1lLHByb1BlcnR5VmFsdWUpOzxiciAvPg0KtdrI/bK9o6zJ+rPJtffTw1dlYlNlcnZpY2Vzt723qLXEU09BUMfrx/PQxc+io6yyotbGtqhTT0FQtcSw5rG+PGJyIC8+DQpTb2FwU2VyaWFsaXphdGlvbkVudmVsb3BlIGVudmVsb3BlID0gbmV3IFNvYXBTZXJpYWxpemF0aW9uRW52ZWxvcGUoU29hcEVudmVsb3BlLlZFUjEwKTs8YnIgLz4NCmVudmVsb3BlLmJvZHlPVXQgPSBycGM7PGJyIC8+DQq12svEsr2jrMn6s8m199PDV2ViU2VydmljZXO3vbeotcRIdHRwVHJhbnNwb3J0U0XKtczlttTP8zxiciAvPg0KSHR0cFRyYW5zcG9ydFNFIHRyYW5zcG9ydCA9IG5ldyBIdHRwVHJhbnNwb3J0U0UoU2VydmljZVVSTCk7PGJyIC8+DQq12s7lsr2jrLX308NjYWxst723qMfrx/O3/s7xPGJyIC8+DQpUcmFuc3BvcnQuY2FsbChzb2FwQWN0aW9uLGVudmVsb3BlKTs8YnIgLz4NCrXawfmyvaOsu/HIobf+zvG2y7e1u9i1xMr9vt08YnIgLz4NClNvYXBPYmplY3Qgb2JqZWN0ID0gKFNvYXBPYmplY3QpZW52ZWxvcGUuYm9keUluOzxiciAvPg0KtdrG37K9o6y94s72t7W72LXEc29hcE9iamVjdLKiu/HIodDo0qq1xMr9vt294bn7PGJyIC8+DQpTdHJpbmcgcmVzdWx0ID0gb2JqZWN0LmdldFByb1BlcnR5KDApLnRvU3RyaW5nKCk7PGJyIC8+DQq21LX308O5/bPMtcS31s72PGJyIC8+DQrXotLiMaO6tdrSu7K9oaK12svEsr2horXazuWyvdbQo6zJ5rywtb2199PDV2ViU2VydmljZXPWrsew0OjSqsWqx+Wz/iZyZHF1bztOYW1lU3BhY2UmcmRxdW87oaImcmRxdW87bWV0aG9kTmFtZSZyZHF1bzuhoiZyZHF1bztzZXJ2aWNlVVJMJnJkcXVvO6GiJnJkcXVvO3NvYXBBY3Rpb24mcmRxdW87oaPV4tCp1rXQ6NKqtNN3c2RszsS1tdbQ0bDV0qOsyOe5+8/rttR3c2RszsS1tcnuyOvRp8+wo6zH67LOv7x3c2Rs0afPsM7EtbWjrLG+zsS1tda7y7XD98jnus6003dzZGzOxLW11tDV0rW9z+DTprXE1rWhozxiciAvPg0Kvau3/s7xtsvM4bmptcR1cmy12Na35K/AwMb3tdjWt8C4v8nS1L+0tb3I58/CvefD5jo8YnIgLz4NCjxpbWcgYWx0PQ=="這裡寫圖片描述" src="/uploadfile/Collfiles/20160503/20160503090547110.png" title="\" />
通過鏈接訪問wsdl文檔,可以看到當前wsdl文檔應用的所得有命名空間,內容界面如下:這裡寫圖片描述
在此文檔中,我們也可以找到我們需要的四個重要的屬性值:
命名空間:找到wsdl:definitions節點,即wsdl的根節點,找到屬性targetNamespace的值,即為我們所需的命名空間nameSpace的值,如圖:
這裡寫圖片描述
這裡寫圖片描述
方法名和SoapAction:找到wsdl:operation節點,其屬性name的值即為我們所需的方法名methodName的值,其子節點soap:operation的屬性SoapAction的值即為當前我們所需方法所對應的soapAction的值,如圖:這裡寫圖片描述
至此,調用webService服務所需的最基本的四個屬性值獲取完成。但調用的過程中一定要保證methodName與soapAction的一一對應關系。
注意2:第二步中,涉及到設置參數。通過wsdl文件中wsdl:types節點的子節點xsd:import
通過第一個URL獲取到當前服務的所有方法、每個方法的所有參數及參數類型
這裡寫圖片描述
通過第二個URL獲取到當前服務所有能直接傳遞的數據類型,即基本數據類型
這裡寫圖片描述
通過第三個URL獲取到當前服務所有自定義類型的參數、參數的所有屬性及屬性類型
這裡寫圖片描述
通過第一個URL訪問到如下界面:
這裡寫圖片描述
針對參數類型,如何判斷參數是不是自定義參數類型呢?可以通過第二個URL跳轉查看服務描述的所有基本數據類型,如下圖:
這裡寫圖片描述
若沒有,通過第三個URL跳轉查看服務描述的所有自定義類型,一一對應的關系,如果沒有在當前鏈接裡找到你所要了解的數據類型,那麼這種數據類型即為復雜類型,或稱自定義類型。需要對自定義類型的屬性加以進一步了解,如下圖:這裡寫圖片描述
若沒有,可以詢問服務端負責人員
自定義數據類型參數問題
針對這種自定義類型的參數,通過第二步中設置參數是達不到我們想要的效果的,服務端返回的信息為”服務器內部錯誤”等。那麼這種情況我們該怎麼解決呢?
下面拿上述TransferParams講解一下:
第一步、在本地新建TransferParams.java文件,實現KvmSerializable序列化接口。
第二步、將上圖中TransferParams參數包含的所有屬性按順序聲明,注意:一定要按順序
第三步、實現getProperty(int arg0)、getPropertyCount()、getPropertyInfo(int arg0,Hashtable arg1,PropertyInfo arg2)、setProperty(int arg0,Object arg1)方法。
getProperty(int arg0) 通過索引獲取指定屬性
getPropertyCount() 獲取屬性集合的大小
getPropertyInfo(int arg0,Hashtable arg1,PropertyInfo arg2)
獲取指定索引的屬性的名稱和類型,注意:方法中第一件事是為參數設置命名空間
setProperty(int arg0,Object arg1) 為指定的屬性賦值
第四步、在調用過程中,添加本地數據類型與服務端數據類型的映射,通過addMapping()方法在調用webService服務的HttpTransportSE對象調用call()方法之前。
addMapping()方法有三個參數,分別是服務端的引用url、參數名和本地對應的類型。代碼如下:envelope.addMapping(soapMapping, “TransferParams”, TransferParams.class);
三個參數可通過自定義參數描述文件中xs:schema節點的targetNamespace屬性值、xs:complexType節點的name屬性值獲取到SoapMapping和TransferParams兩個值。
這樣自定義類型的參數的問題也差不多能解決了。
帶有自定義類型屬性的自定義類型參數
但是此刻就又有問題了,你應該發現了此時自定義類型參數的所有屬性都是基本數據類型,那如果此參數的某個屬性也是自定義類型的,該怎麼解決呢?解決方法與上述自定義類型的解決方法相似,就是新建java文件實現kvmSerializable序列化接口來描述自定義類型的屬性,然後以普通屬性的形式在自定義類型參數中聲明。
自定義類型參數集合
到這裡,自定義類型的參數問題已經解決了一半,剩下的一半是自定義類型參數集合。如果擁有自定義類型屬性的自定義參數你理解了,那麼這剩下的一半自定義類型參數集合就很容易了。這裡你可以把集合想象成一個有且只有一個屬性的參數,而此屬性也為自定類型的。只是不同的是你在新建集合的java文件時,需要繼承Vector,這裡的E指的是集合中包含的參數類型。當然參數類型的映射仍需要添加。

最後,針對上面的資源用一個完整的案例幫助大家分析一下,所以請容我再啰嗦一遍
准備工作
服務地址 http://10.0.1.223:9100/KdtService/
Ksoap2-android.Jar包 下載地址:http://pan.baidu.com/s/1CE754
1、 新建android項目,導入jar包,添加權限
2、 修改activity_main.xml文件,添加三個按鈕分別用於測試無參(基本數據類型)webServices服務調用、自定義參數webServices服務調用、自定義參數集合webServices服務調用和一個用於顯示結果的顯示框,代碼如下:

package com.example.webservicetest;

import java.io.IOException;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;

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 WebServiceOp {
    //命名空間
    private static final String NAME_SPACE = "http://tempuri.org/";
    //服務地址
    private static final String URL = "http://10.0.1.223:9100/KdtService/basic";
    //操作方法的名稱
    private static String methodName = "";
    private static String soapMapping = "http://schemas.datacontract.org/2004/07/WebServiceManager";
    private static LinkedHashMapparamMap;
    private static TransferParamstran;
    private static int flag = 1;
 /**
     * 公用方法
     * @parammethodname方法名稱
     * @paramparamMap   參數集合
     * @return
     * @throws IOException
     */
    public static SoapObjectLoadResult(String methodname,MapparamMap) throws IOException{
//創建soap對象,傳入所需調用的webService的命名空間和webService方法名
    SoapObjectsoapObject = new SoapObject(NAME_SPACE, methodname);
    //創建SoapSerializationEnvelope對象,傳入所需版本
    SoapSerializationEnvelope envelope 
= new SoapSerializationEnvelope(SoapEnvelope.VER11); 
    //創建HttpTransportSE對象,該對象用於調用webService操作
    HttpTransportSE trans = new HttpTransportSE(URL,20000);
    //判斷參數集合是否為空
    if(paramMap != null)
    {
        //將map中的參數放入迭代器中
        Iterator>iter = paramMap.entrySet().iterator();
        //遍歷迭代器,為soap對象設置參數
            while(iter.hasNext()){
                Map.Entry me = iter.next();
                soapObject.addProperty(me.getKey(),"".equals(me.getValue())?null:me.getValue());
            }
            //服務器端自定義類型的映射
            switch(flag)
            {
                case 0:
                    break;
                case 1:
                    envelope.addMapping(soapMapping, "TransferParams", TransferParams.class);
                    break;
                case 2:
                    envelope.addMapping(soapMapping, "TransferParams", TransferParams.class);
                envelope.addMapping(soapMapping, "ParamEnt", ParamEnt.class);
                envelope.addMapping(soapMapping, "ArrayOfParamEnt", ArrayOfPEnt.class);
                    break;
                case 3:
                    envelope.addMapping(soapMapping, "TransferParams", TransferParams.class);
                envelope.addMapping(soapMapping, "ScanData", ScanData.class);
                envelope.addMapping(soapMapping, "ArrayOfScanData", ArrayOfScanData.class);
                    break;

                default:
                    break;
            }

    }
    //創建的SoapObject對象設為SoapSerializationEnvelope的傳出SOAP消息體
envelope.bodyOut = soapObject;
envelope.setOutputSoapObject(soapObject);
        //設置兼容.net服務器端
envelope.dotNet = true;
        //使用調試功能
trans.debug = true; 

        try {
    //調用操作對象call方法,將SoapSerializationEnvelope作為參數調用遠程webService
trans.call(NAME_SPACE + "IKdtService/" + methodname, envelope);
System.out.println(trans.requestDump);
            //調用完成,訪問SoapSerializationEnvelope對象的bodyIn屬性,該屬性返回一個SoapObject對象,該對象代表webService的返回信息
SoapObject result = (SoapObject) envelope.bodyIn;
            //打印Log日志信息
            return result;
        } catch (XmlPullParserException e) {
e.printStackTrace();
            return null;
        }
    }
    //無參調用
    public static SoapObjectserverTime() throws IOException
    {
    methodName = "ServerTime";
    flag = 0;
    return LoadResult(methodName, null);
    }
    //自定義類型參數調用
    public static SoapObject register() throws IOException
    {   //設置需要調用的服務器接口方法的名稱
    methodName = "Register";

    tran = new TransferParams();
    tran.setCompress(true);
    tran.setDBType(0);
    tran.setDefaultLogic(true);
    tran.setEnterpriseID("Thinta");
    tran.setFileType(0);
    tran.setPDAID("1000000");
    tran.setStationID("900001");
    //將自定義類型以參數形式放入map集合中
    paramMap = new LinkedHashMap();
    paramMap.put("param", tran);
    flag = 1;
    return LoadResult(methodName, paramMap);
    }
    //含有自定義類型參數集合的調用
    public static SoapObjectdownLoad() throws IOException
    {
    methodName = "Download";

    tran = new TransferParams();
    tran.setCompress(true);
    tran.setDBType(0);
    tran.setDefaultLogic(true);
    tran.setEnterpriseID("Thinta");
    tran.setFileType(0);
    tran.setPDAID("1000000");
    tran.setStationID("900001");

    ParamEnt p1= new ParamEnt();
    p1.setTableName("SiteInfo");
    ParamEnt p2 = new ParamEnt();
    p2.setTableName("Employee");

    ArrayOfPEntaope = new ArrayOfPEnt();
    aope.add(p1);
    aope.add(p2);

    paramMap = new LinkedHashMap();
    paramMap.put("param", tran);
    paramMap.put("list", aope);
    flag = 2;
    return LoadResult(methodName, paramMap);
    }
}

對於這個類,需要啰嗦幾句。
主要方法是LoadResult(String methodName, Map

package com.example.webservicetest;

import java.util.Hashtable;

import org.ksoap2.serialization.KvmSerializable;
import org.ksoap2.serialization.PropertyInfo;

public class TransferParams implements KvmSerializable{
    private boolean Compress;
    private intDBType;
    private booleanDefaultLogic;
    private String EnterpriseID;
    private intFileType;
    private String MD5;
    private String PDAID;
    private String StationID;
    private String Version;

    @Override
    public Object getProperty(int arg0) {
        switch (arg0) {
        case 0:
            return Compress;
        case 1:
            return DBType;
        case 2:
            return DefaultLogic;
        case 3:
            return EnterpriseID;
        case 4:
            return FileType;
        case 5:
            return MD5;
        case 6:
            return PDAID;
        case 7:
            return StationID;
        case 8:
            return Version;
        default:
            return null;
        }
    }

    @Override
    public intgetPropertyCount() {
        return 9;//參數的個數
    }

    @Override
    public void getPropertyInfo(int arg0, Hashtable arg1, PropertyInfo arg2) {
    //這個很重要
    arg2.namespace="http://schemas.datacontract.org/2004/07/WebServiceManager";       switch (arg0) { 
        case 0: 
    arg2.type=PropertyInfo.BOOLEAN_CLASS; 
    arg2.name="Compress"; 
            break; 
        case 1: 
    arg2.type=PropertyInfo.INTEGER_CLASS; 
    arg2.name="DBType"; 
            break; 
        case 2: 
    arg2.type=PropertyInfo.BOOLEAN_CLASS; 
    arg2.name="DefaultLogic"; 
    break; 
        case 3: 
    arg2.type=PropertyInfo.STRING_CLASS; 
    arg2.name="EnterpriseID"; 
    break; 
        case 4: 
    arg2.type=PropertyInfo.INTEGER_CLASS; 
    arg2.name="FileType"; 
    break; 
        case 5: 
    arg2.type=PropertyInfo.STRING_CLASS; 
    arg2.name="MD5"; 
    break; 
        case 6: 
    arg2.type=PropertyInfo.STRING_CLASS; 
    arg2.name="PDAID"; 
    break; 
        case 7: 
    arg2.type=PropertyInfo.STRING_CLASS; 
    arg2.name="StationID"; 
    break; 
        case 8: 
    arg2.type=PropertyInfo.STRING_CLASS; 
    arg2.name="Version"; 
    break; 
        default: 
            break; 
        } 
    }

    @Override
    public void setProperty(int arg0, Object arg1) {
        switch (arg0) {
        case 0:
            Compress = Boolean.getBoolean(arg1.toString());
            break;
        case 1:
            DBType = Integer.valueOf(arg1.toString());
            break;
        case 2:
            DefaultLogic = Boolean.getBoolean(arg1.toString());
            break;
        case 3:
            EnterpriseID = arg1.toString();
            break;
        case 4:
            FileType = Integer.valueOf(arg1.toString());
            break;
        case 5:
            MD5 = arg1.toString();
            break;
        case 6:
            PDAID = arg1.toString();
            break;
        case 7:
            StationID = arg1.toString();
            break;
        case 8:
            Version = arg1.toString();
            break;
        default:
            break;
        }
    }

    public booleanisCompress() {
        return Compress;
    }

    public void setCompress(boolean compress) {
        Compress = compress;
    }

    public intgetDBType() {
        return DBType;
    }

    public void setDBType(intdBType) {
        DBType = dBType;
    }

    public booleanisDefaultLogic() {
        return DefaultLogic;
    }

    public void setDefaultLogic(booleandefaultLogic) {
        DefaultLogic = defaultLogic;
    }

    public String getEnterpriseID() {
        return EnterpriseID;
    }

    public void setEnterpriseID(String enterpriseID) {
        EnterpriseID = enterpriseID;
    }

    public intgetFileType() {
        return FileType;
    }

    public void setFileType(intfileType) {
        FileType = fileType;
    }

    public String getMD5() {
        return MD5;
    }

    public void setMD5(String mD5) {
        MD5 = mD5;
    }

    public String getPDAID() {
        return PDAID;
    }

    public void setPDAID(String pDAID) {
        PDAID = pDAID;
    }

    public String getStationID() {
        return StationID;
    }

    public void setStationID(String stationID) {
        StationID = stationID;
    }

    public String getVersion() {
        return Version;
    }

    public void setVersion(String version) {
        Version = version;
    }

}

此文件中除了屬性的名稱需要同wsdl文件中的一致,getProperty()、getPropertyInfo()、setProperty()方法中屬性的順序需要注意意外,特別需要注意就是上邊紅色代碼部分,一個是getCount()方法的返回值,一個是getPropertyInfo()方法第三個參數的命名空間的設置。返回值是隨著屬性的改變而改變的,這點一定要注意,如果當前返回值小於屬性的總數,調用的過程中可能會出現數組越界的異常;命名空間也是與wsdl文件中的值對應的,如果命名空間匹配出錯,會影響服務器端的處理及返回值,拿本例來講,如果把命名空間賦值的代碼注釋掉,調用服務返回的結果是ERROR,而命名空間賦值匹配正確的情況下,調用服務返回的結果則是PAD IS REGISTEDS,所以一定要注意命名空間的賦值。除了命名空間的匹配外,我們還需要進行服務端與客戶端對自定義類型的映射,就是那段addMapping添加映射的代碼,第一個參數是服務端自定義類型參數所處的命名空間對應的引用,第二個參數是此類型參數在服務端的參數名稱,第三個參數是客戶端(即本地)該自定義類型的參數所對應的類型。
包括自定義類型、類型映射工作做完並都保證正確之後,再進行服務調用操作,應該就不會出現錯誤了。
自定義類型參數集合(downLoad)在此處代表含有自定義屬性的自定義參數和自定義參數集合的調用服務操作,這裡的參數為ArrayOfPEnt類型,因為它代表的是ParamEnt類型的集合,針對這種自定義類型,我們同樣需要映射,既然要映射,就需要服務器端和客戶端的各自的類型,而此時只有服務器端對這個類型進行了定義,客戶端並沒有對這個類型進行定義,所以接下來的第一件事就是定義ArrayOfPEnt類型。具體作法如下:
5、 新建ParamEnt.java文件,做法同第四步相同,這裡重點說一下ArrayOfPEnt.java文件,實現KvmSerializable接口並繼承Vector容器類,以便起到集合的作用。代碼如下:

package com.example.webservicetest;

import java.util.Hashtable;
import java.util.Vector;

import org.ksoap2.serialization.KvmSerializable;
import org.ksoap2.serialization.PropertyInfo;

public class ArrayOfPEnt extends Vector
        implements
            KvmSerializable
{

    @Override
    public Object getProperty(int arg0)
    {
        return this.get(arg0);
    }

    @Override
    public intgetPropertyCount()
    {
        return this.size();
    }

    @Override
    public void getPropertyInfo(int arg0, Hashtable arg1, PropertyInfo arg2)
    {
//      arg2.namespace = "http://schemas.datacontract.org/2004/07/WebServiceManager";
        arg2.name = "ParamEnt";
        arg2.type = ParamEnt.class;
    }

    @Override
    public void setProperty(int arg0, Object arg1)
    {
        this.add((ParamEnt) arg1);
    }

}

需要注意的地方同第四步,此處不再贅述。
6、 編寫MainActivity.java文件,如下:

package com.example.webservicetest;

import java.io.IOException;

import org.ksoap2.serialization.SoapObject;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.TextureView;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends Activity implements OnClickListener{
    Button b1,b2,b3;
    TextView t;
    private SoapObjectsoapObject = new SoapObject();
    private String resultStr = "";
    private Handler mHandler = null;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        t = (TextView) findViewById(R.id.textView);
        b1 = (Button) findViewById(R.id.simple);
        b2 = (Button) findViewById(R.id.simplecom);
        b3 = (Button) findViewById(R.id.comlist);

        b1.setOnClickListener(this);
        b2.setOnClickListener(this);
        b3.setOnClickListener(this);

        mHandler = new Handler()
        {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                switch (msg.what) {
                case 0x11:
                    t.setText(resultStr);
                    break;
                case 0x12:
                    t.setText(resultStr);
                    break;
                case 0x13:
                    t.setText(resultStr);
                    break;

                default:
                    break;
                }
            }
        };
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
        case R.id.simple:
            new Thread(){
                public void run() {
                    try {
                        soapObject = WebServiceOp.serverTime();
                        resultStr = "請求無參的服務調用-->結果為:" + soapObject.toString();

                        Message msg = new Message();
                        msg.what = 0x11;
                        mHandler.sendMessage(msg);
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                };
            }.start();
            break;
        case R.id.simplecom:
            new Thread()
            {
                public void run() {
                    try {
                        soapObject = WebServiceOp.register();
                        resultStr = "請求自定義參數的服務調用-->結果為:" + soapObject.toString();

                        Message msg = new Message();
                        msg.what = 0x12;
                        mHandler.sendMessage(msg);
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                };
            }.start();
            break;
        case R.id.comlist:
            new Thread()
            {
                public void run() {
                    try {
                        soapObject = WebServiceOp.downLoad();
                        resultStr = "請求自定義參數集合的服務調用-->結果為:" + soapObject.toString();

                        Message msg = new Message();
                        msg.what = 0x13;
                        mHandler.sendMessage(msg);
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                };
            }.start();
            break;
        default:
            break;
        }
    }
}

上面的方法你若是覺得太雜太亂的話,我有寫了一個高度集中的方法,面對任何參數任何類型的,簡單數據類型,自定義對象。。。看看吧

package com.agbc.webservice;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.ksoap2.SoapEnvelope;
import org.ksoap2.SoapFault;
import org.ksoap2.serialization.MarshalBase64;
import org.ksoap2.serialization.MarshalDate;
import org.ksoap2.serialization.MarshalFloat;
import org.ksoap2.serialization.PropertyInfo;
import org.ksoap2.serialization.SoapObject;
import org.ksoap2.serialization.SoapSerializationEnvelope;
import org.ksoap2.transport.HttpTransportSE;
import org.xmlpull.v1.XmlPullParserException;

import sun.management.resources.agent;

import com.agbc.Api.AgbcApi;
import com.agbc.entity.TUser;

import android.content.Context;
import android.graphics.Bitmap;
import android.os.Handler;
import android.os.Message;
import android.os.Messenger;
import android.support.v4.util.LruCache;
import android.util.Log;
/**
 * 請求webservice封裝類
 * 2016/4/10 進行優化,添加三級緩存技術
 * @author double 江
 *
 */
public class WebServiceBase { 
    public static final int SUCCSEE = 0;
    public static final int FAIL = 1;
    private SoapObject      request;
    public WebServiceBase() {
    }
    public WebServiceBase(Context context,Handler handler){
        Executors.newFixedThreadPool(5);

    }
    /**
     * 通過傳遞簡單數據類型參數,
     * 服務端方法名稱獲取范圍webservice的數據,
     * 倒數第二個參數是服務端的方法名,必須與服務端一致。
     *  最後一個參數是服務端url,
     *   
     * @param arg 參數列表Object類型的
     * @return 返回SoapObject類型的原始數據
     */
    public SoapObject getBaseSimpleData(Object...arg){

                final String methodName=arg[(arg.length-2)].toString();
                final String soapAction=AgbcApi.NAMESPACE+methodName;
                request = new SoapObject(AgbcApi.NAMESPACE, methodName);
                for (int i = 0; i < arg.length-2; i++) {
                    request.addProperty("arg"+i, arg[i]);
                    Log.i("arg"+i, arg[i].toString());
                }
                SoapSerializationEnvelope envelope  = new SoapSerializationEnvelope(SoapEnvelope.VER11);    
                (new MarshalBase64()).register(envelope);   
                envelope.bodyOut = request;  
                envelope.dotNet=false;
                envelope.setOutputSoapObject(request);      
                HttpTransportSE ht = new HttpTransportSE(arg[arg.length-1].toString(),10000);  
                ht.debug=true;  
                try {
                    ht.call(soapAction, envelope);
                    if(envelope.bodyIn instanceof SoapFault){
                        String str = ((SoapFault) envelope.bodyIn).faultstring;//返回的是空節點        
                        Log.i("返回錯誤的數據", str);
                    }
                    else {
                        request=(SoapObject) envelope.bodyIn;       
                    Log.i("獲得原始數據", request.toString());    
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (XmlPullParserException e) {
                    e.printStackTrace();
                }
                return request;             
    }; 

    /**
     * 通過傳遞簡單數據類型參數,
     * 服務端方法名稱獲取范圍webservice的數據,
     * 倒數第三個位回調標記 int類型的
     * 倒數第二個參數是服務端的方法名,必須與服務端一致。
     *  最後一個參數是服務端url,
     * @param arg 參數列表Object類型的
     * 
     */
    public SoapObject getBaseSimpleDataByNamespace(Object...arg){

        final String methodName=arg[(arg.length-2)].toString();
        final String soapAction=AgbcApi.NAMESPACETWO+methodName;
        request = new SoapObject(AgbcApi.NAMESPACETWO, methodName);
        for (int i = 0; i < arg.length-2; i++) {
            request.addProperty("arg"+i, arg[i]);
            Log.i("arg"+i, arg[i].toString());
        }
        SoapSerializationEnvelope envelope  = new SoapSerializationEnvelope(SoapEnvelope.VER11);    
        (new MarshalBase64()).register(envelope);   
        envelope.bodyOut = request;  
        envelope.dotNet=false;
        envelope.setOutputSoapObject(request);      
        HttpTransportSE ht = new HttpTransportSE(arg[arg.length-1].toString(),10000);  
        ht.debug=true;  
        try {
            ht.call(soapAction, envelope);
            if(envelope.bodyIn instanceof SoapFault){
                String str = ((SoapFault) envelope.bodyIn).faultstring;//返回的是空節點        
                Log.i("返回錯誤的數據", str);
            }
            else {
                request=(SoapObject) envelope.bodyIn;       
            Log.i("獲得原始數據", request.toString());    
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (XmlPullParserException e) {
            e.printStackTrace();
        }
        return request;             
}; 
//  public void getBaseSimpleData1(final Object...arg){
//      executorService.execute(new Runnable() {
//          @Override
//          public void run() {
//              final String methodName=arg[(arg.length-2)].toString();
//              final String soapAction=AgbcApi.NAMESPACE+methodName;
//              request = new SoapObject(AgbcApi.NAMESPACE, methodName);
//              for (int i = 0; i < arg.length-3; i++) {
//                  request.addProperty("arg"+i, arg[i]);
//                  Log.i("arg"+i, arg[i].toString());
//              }
//              SoapSerializationEnvelope envelope  = new SoapSerializationEnvelope(SoapEnvelope.VER11);    
//              (new MarshalBase64()).register(envelope);   
//              envelope.bodyOut = request;  
//              envelope.dotNet=false;
//              envelope.setOutputSoapObject(request);      
//              HttpTransportSE ht = new HttpTransportSE(arg[arg.length-1].toString(),10000);  
//              ht.debug=true;  
//              try {
//                  ht.call(soapAction, envelope);
//                  if(envelope.bodyIn instanceof SoapFault){
//                      String str = ((SoapFault) envelope.bodyIn).faultstring;//返回的是空節點        
//                      Log.i("返回錯誤的數據", str);
//                      Message message=Message.obtain();
//                      message.what=FAIL;
//                      handler.sendMessage(message);
//                  }
//                  else {
//                      request=(SoapObject) envelope.bodyIn;   
//                      Log.i("獲得原始數據", request.toString());    
//                   message=Message.obtain();
//                  message.obj=request;
//                  message.what=(int) arg[arg.length-3];
//                  handler.sendMessage(message);
//                  
//                  }
//              } catch (IOException e) {
//                  e.printStackTrace();
//              } catch (XmlPullParserException e) {
//                  e.printStackTrace();
//              }               
//          }
//      });
//  }; 

    /**
     * 傳遞自定義數據類型對象(序列化後)。
     * 1,自定義類對象,
     * 2,方法名稱,與服務端一直
     * 3,請求的的service
     * @return
     */
    public SoapObject getBaseComplexData(Object ...arg){
        String methodName = arg[arg.length-2].toString().trim();//請求方法名
        Log.i("方法名稱", arg[arg.length-2].toString());
        String soapAction = arg[(arg.length-1)].toString()+methodName;
        Log.i("參數", arg[(arg.length-1)].toString());
        // 建立webservice連接對象
        HttpTransportSE transport = new HttpTransportSE(arg[(arg.length-1)].toString(),10000);//10秒超時
        transport.debug = true;// 是否是調試模式
        // 設置連接參數
        SoapObject soapObject = new SoapObject(AgbcApi.NAMESPACE, methodName);
        PropertyInfo objekt = new PropertyInfo();

        objekt.setName("arg0");
        objekt.setValue(arg[0]);
        objekt.setType(arg[0].getClass());
        soapObject.addProperty(objekt);

        // 設置返回參數
        SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);// soap協議版本必須用SoapEnvelope.VER11(Soap
        envelope.dotNet = false;// 注意:這個屬性是對dotnetwebservice協議的支持,如果dotnet的webservice
        envelope.bodyOut = transport;
        Log.i("請求參數", soapObject.toString());
        envelope.setOutputSoapObject(soapObject);// 設置請求參數
        new MarshalDate().register(envelope);
        envelope.addMapping(AgbcApi.NAMESPACE, methodName,arg[0].getClass());// 傳對象時必須,參數namespace是webservice中指定的,

        (new MarshalBase64()).register(envelope);
        new MarshalFloat().register(envelope);
        try {
            transport.call(soapAction, envelope);
            if(envelope.bodyIn instanceof SoapFault){
                String str = ((SoapFault) envelope.bodyIn).faultstring;
                Log.i("錯誤信息", str);
            }
            else {
                request=(SoapObject) envelope.bodyIn;
                Object obj = envelope.getResponse();// 直接將返回值強制轉換為已知對象
                Log.i("返回的原始數據obj", obj.toString());
                Log.i("返回的原始數據request", request.toString());
                return  request;
            }
        }
        catch (IOException e) {
            e.printStackTrace();
        }
        catch (XmlPullParserException e) {
            e.printStackTrace();
        }
        catch (Exception ex) {
            ex.printStackTrace();
        }
        // 解析返回的結果  
        return null;

    };



    /**
     * 傳遞自定義數據類型對象(序列化後)。
     * 1,自定義類對象,
     * 2,方法名稱,與服務端一直
     * 3,請求的的service
     * @return
     */
    public SoapObject getBaseComplexDataNamespace(Object ...arg){
        String methodName = arg[arg.length-2].toString().trim();//請求方法名
        Log.i("方法名稱", arg[arg.length-2].toString());
        String soapAction = arg[(arg.length-1)].toString()+methodName;
        Log.i("參數", arg[(arg.length-1)].toString());
        // 建立webservice連接對象
        HttpTransportSE transport = new HttpTransportSE(arg[(arg.length-1)].toString(),10000);//10秒超時
        transport.debug = true;// 是否是調試模式

        // 設置連接參數
        SoapObject soapObject = new SoapObject(AgbcApi.NAMESPACETWO, methodName);
        //soapObject.addProperty("", String.valueOf(1));
        PropertyInfo objekt = new PropertyInfo();

        objekt.setName("arg0");
        objekt.setValue(arg[0]);
        Log.i("類", arg[0].toString());
        objekt.setType(TUser.class);
        soapObject.addProperty(objekt);

        // 設置返回參數
        SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);// soap協議版本必須用SoapEnvelope.VER11(Soap
        envelope.implicitTypes=true;
        envelope.dotNet = false;// 注意:這個屬性是對dotnetwebservice協議的支持,如果dotnet的webservice
        //envelope.implicitTypes = true;
        envelope.bodyOut = transport;
        Log.i("請求參數", soapObject.toString());
        envelope.setOutputSoapObject(soapObject);// 設置請求參數
        new MarshalDate().register(envelope);
        envelope.addMapping(AgbcApi.NAMESPACETWO, methodName, TUser.class);// 傳對象時必須,參數namespace是webservice中指定的,

        (new MarshalBase64()).register(envelope);
        new MarshalFloat().register(envelope);
        try {
            transport.call(soapAction, envelope);
            if(envelope.bodyIn instanceof SoapFault){
                String str = ((SoapFault) envelope.bodyIn).faultstring;
                Log.i("錯誤信息", str);

            }
            else {
                request=(SoapObject) envelope.bodyIn;
                Object obj = envelope.getResponse();// 直接將返回值強制轉換為已知對象
                Log.i("返回的原始數據obj", obj.toString());
                Log.i("返回的原始數據request", request.toString());
                return  request;
            }
        }
        catch (IOException e) {
            e.printStackTrace();
        }
        catch (XmlPullParserException e) {
            e.printStackTrace();
        }
        catch (Exception ex) {
            ex.printStackTrace();
        }
        // 解析返回的結果  
        return null;

    };
}

思來想去我還是覺得應該把這個在Activity中訪問網絡的問題啰嗦一下,由於android 4.0以上版本系統不支持主線程存在耗時操作(包括訪問網絡和大數據計算等),所以需要通過一個線程來處理,如上述代碼中的紅色標注部分。解決方案有很多種,最常用的為handler+thread、AsyncTask兩種方式,在此不再贅述,我的下一篇博客吧
至此,整個項目差不多完成了,部署,測試一下。對此,你要是在不會用webservice。我就沒法了。。。。。。

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