您好,登錄后才能下訂單哦!
在在網(wǎng)絡(luò)APP中有2個(gè)非常重要的節(jié)
客戶端請(qǐng)求服務(wù)端接口的能力
客戶端,服務(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)期待吧。
免責(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)容。