Android okHttp網路請求之Json解析

總李寫程式碼發表於2016-05-27

  前言:

  前面兩篇文章介紹了基於okHttp的post、get請求,以及檔案的上傳下載,今天主要介紹一下如何和Json解析一起使用?如何才能提高開發效率?

     okHttp相關文章地址:

 關於Json解析:

  本文的Json解析採用阿里巴巴的FastJson 解析,也可以採用Gson解析,兩者之間的對比請參考文章Android之json解析(FastJson Gson 對比)(http://www.cnblogs.com/whoislcj/p/5468420.html)。

 關於泛型:

  本文將採用json統一泛型解析,閱讀本文之前請先對java泛型知識有一定的瞭解。

 關於反射機制:

 本文會採用Java的反射機制來解析泛型物件Class<?>,閱讀本文之前請先對Java發射機制知識有一定的瞭解。

程式碼實現:

1.)首先我們宣告一個TypeInfo.java類用來封裝泛型相關屬性
import java.lang.reflect.Array;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

public class TypeInfo {
    //Type泛型物件型別
    private Class<?> componentType;
    //Type所屬物件型別
    private Class<?> rawType;
    //type
    private Type type;

    private TypeInfo(Class<?> rawType, Class<?> componentType) {

        this.componentType = componentType;
        this.rawType = rawType;
    }

    public static TypeInfo createArrayType(Class<?> componentType) {
        return new TypeInfo(Array.class, componentType);
    }

    public static TypeInfo createNormalType(Class<?> componentType) {
        return new TypeInfo(null, componentType);
    }

    public static TypeInfo createParameterizedType(Class<?> rawType, Class<?> componentType) {
        return new TypeInfo(rawType, componentType);
    }

    public TypeInfo(Type type) {
        this.type = type;
        if (type instanceof ParameterizedType) {
            //返回 Type 物件,表示宣告此型別的類或介面。
            this.rawType = (Class<?>) ((ParameterizedType) type).getRawType();
            //getActualTypeArguments()返回表示此型別實際型別引數的 Type 物件的陣列。
            Type[] actualTypeArguments = ((ParameterizedType) type).getActualTypeArguments();
            this.componentType = (Class<?>) actualTypeArguments[0];
            // typeReference=new TypeReference<Map<componentType,componentType>>(){};

        } else if (type instanceof GenericArrayType) {
            //返回 Type 物件,表示宣告此型別的類或介面。
            this.rawType = Array.class;
            // 表示一種元素型別是引數化型別或者型別變數的陣列型別
            this.componentType = (Class<?>) ((GenericArrayType) type).getGenericComponentType();
        } else {
            this.componentType = (Class<?>) type;
        }
    }

    public Type getType() {
        return type;
    }

    public Class<?> getComponentType() {
        return componentType;
    }


    public Class<?> getRawType() {
        return rawType;
    }

}
2.)宣告ReqClassUtils.java類 用於通過反射機制獲取泛型物件的TypeInfo
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

public class ReqClassUtils {

    public static TypeInfo getCallbackGenericType(Class<?> clazz) {
        //獲得帶有泛型的父類
        Type genericSuperclass = clazz.getGenericSuperclass();//Type是 Java 程式語言中所有型別的公共高階介面。它們包括原始型別、引數化型別、陣列型別、型別變數和基本型別。
        TypeInfo type = getGetnericType(genericSuperclass);
        if (type == null) {
            Type[] genericInterfaces = clazz.getGenericInterfaces();
            if (genericInterfaces != null && genericInterfaces.length > 0) {
                type = getGetnericType(genericInterfaces[0]);
            }
        }
        return type;
    }

    private static TypeInfo getGetnericType(Type type) {
        if (type != null && type instanceof ParameterizedType) {
            //getActualTypeArguments獲取引數化型別的陣列,泛型可能有多個
            Type[] args = ((ParameterizedType) type).getActualTypeArguments();
            if (args != null && args.length > 0) {
                return new TypeInfo(args[0]);
            }
        }
        return null;
    }
}
3.)接下來重點來了,宣告一個json解析工具類ReqJsonUtils.java,主要用於通過TypeInfo相關屬性進行不同型別的json解析
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import java.lang.reflect.Array;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import static com.alibaba.fastjson.JSON.parseObject;

public class ReqJsonUtils {

    //基本型別對映關係Map
    private static final Map primitiveWrapperTypeMap = new HashMap(8);

    static {
        //新增基本型別
        primitiveWrapperTypeMap.put(Boolean.class, boolean.class);
        primitiveWrapperTypeMap.put(Byte.class, byte.class);
        primitiveWrapperTypeMap.put(Character.class, char.class);
        primitiveWrapperTypeMap.put(Double.class, double.class);
        primitiveWrapperTypeMap.put(Float.class, float.class);
        primitiveWrapperTypeMap.put(Integer.class, int.class);
        primitiveWrapperTypeMap.put(Long.class, long.class);
        primitiveWrapperTypeMap.put(Short.class, short.class);
    }

    /**
     * 將JSON字串轉換成指定的使用者返回值型別
     *
     * @param type
     * @param jsonData
     * @return
     * @throws JSONException
     */
    public static <T> T parseHttpResult(TypeInfo type, String jsonData) throws JSONException {
        // 處理Void型別的返回值
        if (Void.class.isAssignableFrom(type.getComponentType())) {
            return null;
        }
        //獲取當前type的資料型別
        Class<?> rawType = type.getRawType();
        //是否是Array
        boolean isArray = rawType != null && Array.class.isAssignableFrom(rawType);
        //是否是Collection
        boolean isCollection = rawType != null && Collection.class.isAssignableFrom(rawType);
        //是否是Map
        boolean isMap = rawType != null && Map.class.isAssignableFrom(rawType);
        //獲取泛型型別
        Class<?> componentType = type.getComponentType();
        //宣告結果物件
        T result = null;
        if (isCollection) {//處理collection
            result = (T) JSON.parseArray(jsonData, componentType);
        } else if (isArray) {//處理array
            result = (T) JSON.parseArray(jsonData, componentType).toArray();
        } else if (isMap) {//處理Map
            result = (T) JSONObject.parseObject(jsonData, type.getType());
        } else if (componentType.isAssignableFrom(String.class)) {//處理字串返回值
            return (T) jsonData;
        } else {
            // 介面的返回型別如果是簡單型別,則會封裝成為一個json物件,真正的物件儲存在value屬性上
            if (isPrimitiveOrWrapper(componentType)) {
                result = (T) parseObject(jsonData);
            } else {
                //處理自定義物件
                result = (T) parseObject(jsonData, componentType);
            }
        }
        return result;
    }

    /**
     * 判斷是否是基本資料型別
     *
     * @param clazz
     * @return
     */
    public static boolean isPrimitiveOrWrapper(Class clazz) {
        return (clazz.isPrimitive() || isPrimitiveWrapper(clazz));
    }

    /**
     * 判斷是否是基本資料型別
     *
     * @param clazz
     * @return
     */
    public static boolean isPrimitiveWrapper(Class clazz) {
        return primitiveWrapperTypeMap.containsKey(clazz);
    }
}

 

如何使用?

1.)實現解析
 TypeInfo typeInfo = ReqClassUtils.getCallbackGenericType(callBack.getClass());
 callBack.onReqSuccess(ReqJsonUtils.parseHttpResult(typeInfo, jsonData));
2.)傳送請求
        HashMap<String, String> paramsMap = new HashMap<>();
        paramsMap.put("sourceType", "2");
        paramsMap.put("sourceDesc", "[Android]" + Build.VERSION.RELEASE + "[Mobel]" + Build.BRAND + " " + Build.MODEL + Build.DEVICE);
        HashMap<String, String> params = dealStringBody(paramsMap);
        RequestManager.getInstance(this).requestAsyn("xxx/actionUrl", RequestManager.TYPE_POST_JSON, params, new ReqCallBack<String>() {

            @Override
            public void onReqSuccess(String result) {
                request_tv.setText(result);
            }

            @Override
            public void onReqFailed(String errorMsg) {

            }
        });
3.)支援型別
        new ReqCallBack<List<Object>>();//集合collection
        new ReqCallBack<Map<String, User>>();//map
        new ReqCallBack<Void>();//Void
        new ReqCallBack<Long>();//基礎型別

 

小結:如此一來傳送請求到解析資料變得So easy !用流行的一句廣告語來說的話,那就是老闆再也不用擔心我搞不定網路請求和json解析了。

 

相關文章