溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Android調(diào)用WebService系列之KSoap2對(duì)象解析

發(fā)布時(shí)間:2020-08-11 21:19:50 來(lái)源:網(wǎng)絡(luò) 閱讀:2339 作者:時(shí)尚倉(cāng)頡 欄目:移動(dòng)開(kāi)發(fā)

在在網(wǎng)絡(luò)APP中有2個(gè)非常重要的節(jié)

  1. 客戶端請(qǐng)求服務(wù)端接口的能力

  2. 客戶端,服務(wù)端的對(duì)接

而我的Android調(diào)用WebService系列共四篇這是最后一篇,所要講述的只僅僅是Android調(diào)用WebService這一種比較少用且不推薦用,但是在一些特定的場(chǎng)合下不得不用的調(diào)用方式。 

Android調(diào)用WebService系列之封裝能力,Android調(diào)用WebService系列之請(qǐng)求調(diào)用是講的請(qǐng)求服務(wù)端的能力主要是介紹APP如何擁有,或者說(shuō)更好的更方便的擁有這種能力

而Android調(diào)用WebService系列之對(duì)象構(gòu)建傳遞,和本文章《Android調(diào)用WebService系列之KSoap2對(duì)象解析》就是講的客戶端,服務(wù)端的對(duì)接,也是我們俗稱的握手,但又不完全是對(duì)接,只能說(shuō)是部分幫助對(duì)接完成的工具。

(當(dāng)你的服務(wù)端全部由自己開(kāi)發(fā)的時(shí)候,你完全可以對(duì)接不搞那么復(fù)雜的對(duì)象,僅用String自定義GSON,JSON握手即可。)

接下來(lái)我要講述的是KSoap2傳遞對(duì)象回來(lái)的時(shí)候我們?cè)撊绾翁幚恚?/span>

首先我們要了解一下服務(wù)端傳遞回的流被KSoap2解析并保存了什么。

    /**
     * The body object received with this envelope. Will be an KDom Node for
     * literal encoding. For SOAP Serialization, please refer to
     * SoapSerializationEnvelope.
     */
    public Object bodyIn;
    /**
     * The body object to be sent with this envelope. Must be a KDom Node
     * modelling the remote call including all parameters for literal encoding.
     * For SOAP Serialization, please refer to SoapSerializationEnvelope
     */
    public Object bodyOut;


當(dāng)我們call之后,我們只需要獲取bodyIn或者調(diào)用getResponse()就可以獲得返回值。

我們看看getResponse方法的源代碼


   
    /**
     * Response from the soap call. Pulls the object from the wrapper object and
     * returns it.
     * 
     * @since 2.0.3
     * @return response from the soap call.
     * @throws SoapFault
     */
    public Object getResponse() throws SoapFault {
        if (bodyIn instanceof SoapFault) {
            throw (SoapFault) bodyIn;
        }
        KvmSerializable ks = (KvmSerializable) bodyIn;
        return ks.getPropertyCount() == 0 ? null : ks.getProperty(0);
    }

返回的是將bodyIn轉(zhuǎn)換成KvmSerializable獲取對(duì)象的第一個(gè)屬性值傳回來(lái)。這時(shí)候我們可能會(huì)想,我們可不可以定義一個(gè)類型然后直接讓bodyIn直接返回該類型呢?很抱歉KSoap2并沒(méi)提供這樣的方式。

那這個(gè)返回的對(duì)象是什么呢?

我們通過(guò)調(diào)試跟蹤發(fā)現(xiàn),這個(gè)值其實(shí)要么是SoapFault要么是SoapObject是實(shí)現(xiàn)了KvmSerializable接口的。

那么我們能不能直接強(qiáng)制轉(zhuǎn)換成我們要的類呢,很遺憾的發(fā)現(xiàn),我們不能直接這樣強(qiáng)轉(zhuǎn)。

我們看看SoapObject的定義是怎么樣的。

/* Copyright (c) 2003,2004, Stefan Haustein, Oberhausen, Rhld., Germany
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The  above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE. 
 *
 * Contributor(s): John D. Beatty, Dave Dash, Andre Gerard, F. Hunter,
 * Renaud Tognelli
 *
 * */

package org.ksoap2.serialization;

import java.util.*;

/**
 * A simple dynamic object that can be used to build soap calls without
 * implementing KvmSerializable
 * 
 * Essentially, this is what goes inside the body of a soap envelope - it is the
 * direct subelement of the body and all further subelements
 * 
 * Instead of this this class, custom classes can be used if they implement the
 * KvmSerializable interface.
 */

public class SoapObject implements KvmSerializable {

    String namespace;
    String name;
    Vector info = new Vector();
    Vector data = new Vector();

    /**
     * Creates a new <code>SoapObject</code> instance.
     * 
     * @param namespace
     *            the namespace for the soap object
     * @param name
     *            the name of the soap object
     */

    public SoapObject(String namespace, String name) {
        this.namespace = namespace;
        this.name = name;
    }

    public boolean equals(Object o) {
        if (!(o instanceof SoapObject))
            return false;

        SoapObject so = (SoapObject) o;
        int cnt = data.size();

        if (cnt != so.data.size())
            return false;

        try {
            for (int i = 0; i < cnt; i++)
                if (!data.elementAt(i).equals(so.getProperty(((PropertyInfo) info.elementAt(i)).name)))
                    return false;
        } catch (Exception e) {
            return false;
        }
        return true;
    }

    public String getName() {
        return name;
    }

    public String getNamespace() {
        return namespace;
    }

    /**
     * Returns a specific property at a certain index.
     * 
     * @param index
     *            the index of the desired property
     * @return the desired property
     */
    public Object getProperty(int index) {
        return data.elementAt(index);
    }

    public Object getProperty(String name) {
        for (int i = 0; i < data.size(); i++) {
            if (name.equals(((PropertyInfo) info.elementAt(i)).name))
                return data.elementAt(i);
        }
        throw new RuntimeException("illegal property: " + name);
    }

    /**
     * Returns the number of properties
     * 
     * @return the number of properties
     */
    public int getPropertyCount() {
        return data.size();
    }

    /**
     * Places PropertyInfo of desired property into a designated PropertyInfo
     * object
     * 
     * @param index
     *            index of desired property
     * @param propertyInfo
     *            designated retainer of desired property
     */
    public void getPropertyInfo(int index, Hashtable properties, PropertyInfo propertyInfo) {
        PropertyInfo p = (PropertyInfo) info.elementAt(index);
        propertyInfo.name = p.name;
        propertyInfo.namespace = p.namespace;
        propertyInfo.flags = p.flags;
        propertyInfo.type = p.type;
        propertyInfo.elementType = p.elementType;
    }

    /**
     * Creates a new SoapObject based on this, allows usage of SoapObjects as
     * templates. One application is to set the expected return type of a soap
     * call if the server does not send explicit type information.
     * 
     * @return a copy of this.
     */
    public SoapObject newInstance() {
        SoapObject o = new SoapObject(namespace, name);
        for (int i = 0; i < data.size(); i++) {
            PropertyInfo propertyInfo = (PropertyInfo) info.elementAt(i);
            o.addProperty(propertyInfo, data.elementAt(i));
        }
        return o;
    }

    /**
     * Sets a specified property to a certain value.
     * 
     * @param index
     *            the index of the specified property
     * @param value
     *            the new value of the property
     */
    public void setProperty(int index, Object value) {
        data.setElementAt(value, index);
    }

    /**
     * Adds a property (parameter) to the object. This is essentially a sub
     * element.
     * 
     * @param name
     *            The name of the property
     * @param value
     *            the value of the property
     */
    public SoapObject addProperty(String name, Object value) {
        PropertyInfo propertyInfo = new PropertyInfo();
        propertyInfo.name = name;
        propertyInfo.type = value == null ? PropertyInfo.OBJECT_CLASS : value.getClass();
        return addProperty(propertyInfo, value);
    }

    /**
     * Adds a property (parameter) to the object. This is essentially a sub
     * element.
     * 
     * @param propertyInfo
     *            designated retainer of desired property
     * @param value
     *            the value of the property
     */
    public SoapObject addProperty(PropertyInfo propertyInfo, Object value) {
        info.addElement(propertyInfo);
        data.addElement(value);
        return this;
    }

    public String toString() {
        StringBuffer buf = new StringBuffer("" + name + "{");
        for (int i = 0; i < getPropertyCount(); i++) {
            buf.append("" + ((PropertyInfo) info.elementAt(i)).name + "=" + getProperty(i) + "; ");
        }
        buf.append("}");
        return buf.toString();
    }

}

看到這,我們發(fā)現(xiàn)他的數(shù)據(jù)用2個(gè)Vector存儲(chǔ)info和data。

那么我們?cè)趺慈。?/p>

網(wǎng)上有很多文章基本上都是直接通過(guò)循環(huán)取下標(biāo)值的方式然后依次進(jìn)行

我們跟蹤發(fā)現(xiàn),KSoap2封裝后傳回的SoapObject是一次嵌套排序所有借點(diǎn)內(nèi)容。意味著如果你類中有個(gè)列表,那么也是依次排列的。而且最糟糕的是你會(huì)發(fā)現(xiàn)所有name都是anyType。這樣意味著我們也將不能直接通過(guò)循環(huán)下標(biāo)賦值的方式將他序列化到類。而且就算可以我們每一個(gè)地方要寫(xiě)的代碼量,做的重復(fù)枯燥的工作就要增加很多。

顯然這樣并不是我們想要的。我們需要的是一個(gè)直接傳遞回來(lái)SoapObject然后直接將SoapObject轉(zhuǎn)換成我們所需要的類。

于是我寫(xiě)了下面這個(gè)類。

原理很簡(jiǎn)單,就是通過(guò)獲取SoapObject字符串,將SoapObject的字符串改變成GSON字符串由Gson轉(zhuǎn)換成我們要的類!

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.ksoap2.serialization.SoapObject;
import org.ksoap2.serialization.SoapPrimitive;

import com.google.gson.Gson;
import android.util.Log;

/**
 * 對(duì)象傳輸基礎(chǔ)類
 * 
 * @author 劉亞林
 * @e-mail 461973266@qq.com
 * 
 */
public class SoapObjectToClass {
	private static final String CLASSTAG = SoapObjectToClass.class.getName();

	/**
	 * 首字母大寫(xiě)
	 * 
	 * @param str
	 * @return
	 */
	public static String upCase(String str) {
		return String.valueOf(str.charAt(0)).toUpperCase()
				.concat(str.substring(1));
	}

	/**
	 * 片段是否是列表
	 * 
	 * @param cls
	 * @return
	 */
	public static boolean isList(Class cls) {
		if (cls.isAssignableFrom(List.class)
				|| cls.isAssignableFrom(ArrayList.class)) {
			return true;
		}
		return false;
	}

	/**
	 * soapobject轉(zhuǎn)類
	 * 
	 * @param clazz
	 * @param soapObject
	 * @return
	 */
	public static <T extends BaseKvmSerializable> T soapToClass(Class<T> clazz,
			SoapObject soapObject) {
		String result = soapToGson(clazz, soapObject);
		System.out.println("result:" + result);
		T t = getFromGson(result, clazz);
		return t;
	}

	private static final Gson GSON_CONVERTER = new Gson();

	/**
	 * 通過(guò)GSON
	 * 
	 * @param value
	 * @param cls
	 * @return
	 */
	public static <T> T getFromGson(String value, Class<T> cls) {

		if (value != null && !value.equals("")) {
			try {
				return GSON_CONVERTER.fromJson(value, cls);
			} catch (Exception e) {
				Log.w(CLASSTAG, "JsonSyntaxException " + e.getCause());
			}
		}
		return null;
	}

	/**
	 * 如果里面=的數(shù)量大于1則認(rèn)定為復(fù)雜類型
	 * 
	 * @param soStr
	 * @return
	 */
	public static boolean isDiffType(String soStr) {
		String rlstr = soStr.replace(":", "");
		if (soStr.length() - rlstr.length() > 0) {
			return true;
		}
		return false;
	}

	/**
	 * 將soapObject類型向json類型靠
	 * 
	 * @param str
	 * @return
	 */
	public static String replaceStr(String str) {
		return str.replace("=", ":").replace("; }", "}").replace(";", ",")
				.replace("anyType{}", "\"\"").replace("anyType", "");
	}

	/**
	 * 獲取已經(jīng)讀取過(guò)了的字符起始值
	 * 
	 * @param str
	 * @param value
	 * @return
	 */
	public static int getSubLen(String str, String value) {
		int index = str.indexOf(value);
		return index + value.length();
	}

	/**
	 * 通過(guò)復(fù)雜對(duì)比的形式獲取到name
	 * 
	 * @param str
	 * @param value
	 * @return
	 */
	public static String getNameByValue(String str, String value) {
		int index = str.indexOf(value);
		String sbStr = str.substring(0, index);
		int lastdotindex = sbStr.lastIndexOf(",");
		int lastkindex = sbStr.lastIndexOf("{");
		int endindex = sbStr.lastIndexOf(":");
		int startindex = lastdotindex > lastkindex ? lastdotindex : lastkindex;
		String result = sbStr.substring(startindex + 1, endindex);
		return result.trim();
	}

	/**
	 * soap對(duì)象轉(zhuǎn)jsonString
	 * 
	 * @param clazz
	 * @param soapObject
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static <T> String soapToGson(Class<T> clazz, SoapObject soapObject) {
		String result = soapObject.toString();
		result = replaceStr(result);
		int sublen = 0;
		int soapCount = soapObject.getPropertyCount();
		HashMap<String, List<String>> rlmap = new HashMap<String, List<String>>();
		for (int i = 0; i < soapCount; i++) {
			Object childObject = soapObject.getProperty(i);
			if (childObject.getClass().isAssignableFrom(SoapPrimitive.class)) {
				continue;
			} else {
				SoapObject so = (SoapObject) childObject;
				String soStr = replaceStr(so.toString());
				if (isDiffType(soStr)) {
					String name = getNameByValue(result.substring(sublen),
							soStr);
					sublen = getSubLen(result, soStr);
					try {
						Field f = clazz.getDeclaredField(name);
						if (f != null) {
							if (isList(f.getType())) {
								Type fc = f.getGenericType();
								if (fc == null) {
									continue;
								}
								if (fc instanceof ParameterizedType) {
									ParameterizedType pt = (ParameterizedType) fc;
									Class genericClazz = (Class) pt
											.getActualTypeArguments()[0];
									soStr = soapToGson(genericClazz, so);
								}
								List<String> list;
								if (rlmap.containsKey(name)) {
									list = rlmap.get(name);
								} else {
									list = new ArrayList<String>();
								}
								list.add(soStr);
								rlmap.put(name, list);
							}
						}
					} catch (NoSuchFieldException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}
		}
		Iterator iter = rlmap.entrySet().iterator();
		while (iter.hasNext()) {
			Map.Entry entry = (Map.Entry) iter.next();
			String key = (String) entry.getKey();
			List<String> val = (List<String>) entry.getValue();
			String listData = "[";
			String rplstr = "";
			int count = val.size();
			for (int i = 0; i < count; i++) {
				if (i == count - 1) {
					rplstr += key + ":" + val.get(i);
				} else {
					rplstr += key + ":" + val.get(i) + ",";
				}
			}
			result = result
					.trim()
					.replace(" ", "")
					.replace(rplstr.trim().replace(" ", ""),
							key + ":" + val.toString());

		}
		return result;
	}

	// private static boolean hasMethod(String methodName, Method[] method) {
	// for (Method m : method) {
	// if (methodName.equals(m.getName())) {
	// return true;
	// }
	// }
	// return false;
	// }
}

注意:BaseKvmSerializable缺少引用,這個(gè)類就是Android調(diào)用WebService系列之對(duì)象構(gòu)建傳遞里面所提到的對(duì)象構(gòu)建傳遞類。

有了這個(gè)類我們只需調(diào)用soapToClass就可以獲取到我們想要的類了。當(dāng)然你也可以調(diào)用soapToGson然后來(lái)獲取gson字符串!

到此,我的Android調(diào)用WebService系列的四篇文章就結(jié)束了。

接下來(lái)我將慢慢的整理一套比較基礎(chǔ)又帶一點(diǎn)特殊的東西,敬請(qǐng)期待吧。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI