天天看點

Android的json詳解

android中json編碼和解碼最常用的有三種:

(1)、安卓自帶的org.json.JSONArray、JSONObject。

(2)、谷歌提供的Gson包。

(3)、阿裡巴巴的fastJson。

1、org.json中的JSONObject和JSONArray。

a、JSONObject是JSON對象的鍵值對,例如:{“name”:”bobo”, “age”:”10”}。

b、JSONArrays是JSON的數組,例如[“aa”, “bb”. {“name”:”bobo”, “age”:10}]。

c、JSONObject 和 JSONArrays隻能接收String對象,當然String對象必須是JSON結構的字元串,否則解析失敗。

d、JSONObject 和 JSONArrays對于解析接收來的json字元串比較友善,如果需要打包成json資料則比較繁瑣,建議不要使用。當然,如果接收的json字元串比較複雜,則JSONObject 和JSONArrays解析就非常複雜,這個時候采用Gson和fastJson就比較友善了。

代碼:
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("name", "bobo");
            jsonObject.put("age", );
            String strResult = jsonObject.toString();
            Log.d("custom_json :", strResult);
輸出結果為:strResult = {"name":"bobo", "age":"10"};

代碼:
            JSONArray jsonArray = new JSONArray();
            jsonArray.put("person");
            jsonArray.put("books");
            jsonArray.put(jsonObject);
            String arrStr = jsonArray.toString();
            Log.d("custom_json :", arrStr);
輸出結果:
//        [
//           "person",
//           "books",
//            {
//                  "name":"bobo",
//                  "age":"10"
//             }
//        ]
           

2、Gson是谷歌提供的專用安卓的json第三方編碼解碼包,使用之前需要找個網站下載下傳這個jar包,然後引用自己的工程。

(1)、注解Expose、SerializedName、Unitl、Since。

a、Expose(serialize = false,deserialize = false)本注解指定哪些字段可以序 列化或反序列化,但是設定 GsonBuilder.excludeFieldsWithoutExposeAnnotation 才有用。

b、SerializedName修改字段的别名,例如SerializedName(“iD”)。

c、Unitl指定某個字段在某個版本之前可被識别,Since表示某個字段在本版本及其之後才能被識别,主要是為了版本的相容。

(2)、FieldNamingPolicy,枚舉值分别有:IDENTITY、UPPER_CAMEL_CASE、UPPER_CAMEL_CASE_WITH_SPACES、LOWER_CASE_WITH_UNDERSCORES、LOWER_CASE_WITH_DASHES。

a、FieldNamingPolicy中的幾個枚舉值,IDENTITY表示字段名不變。

b、UPPER_CAMEL_CASE:導出的字段名稱首字母變成大寫,例如:someFieldName —> SomeFieldName。

c、UPPER_CAMEL_CASE_WITH_SPACES: 将字段名的每個大寫字母開頭的用空格分開,例如:someFieldName —> Some Field Name。

d、 LOWER_CASE_WITH_UNDERSCORES:将字段每個大寫字母開頭的用下劃線(_)分開,并将分開的字元串全部轉成小寫,例如:someFieldName —> some_field_name。

e、LOWER_CASE_WITH_DASHES:将字段每個大寫字母開頭的用破折号(-)分開,并将分開的字元串全部轉成小寫,例如:someFieldName —> some-field-name。

設定的FieldNamingPolicy對于已經設定注解的SerializedName沒有影響,因為注解的優先級高于FieldNamingPolicy的設定。
           

(3)、TypeToken指定序列化對象的類型。

(4)、ExcludeFieldsWithoutExposeAnnotation(),對序列化的對象進行篩選,隻有注解标注有expose且serialize = true的才會被序列化,deserialize = true才會被反序列化。

(5)、enableComplexMapKeySerialization,可以對複雜的map進行序列化。

(6)、代碼測試。

代碼:
package com.example.kingsoft.ObjectLibs;

import com.example.kingsoft.CustomUtil.GsonUtil;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
import com.google.gson.annotations.Until;

/**
 * Created by qiubowang on 2017/6/7
 *
 * Expose(serialize = false,deserialize = false)本注解指定哪些字段可以序列化或反序列化,但是設定GsonBuilder.excludeFieldsWithoutExposeAnnotation才有用
 */

public class Person {
    @Expose(serialize = true,deserialize = false)
    private String mName = null;
    @Expose(serialize = true)
    private int mAge = -;
    @Expose(serialize = false)
    private String mAddress = null;
    @Expose(serialize = false)
    private String mSchool = null;
    @SerializedName("iD")
    @Expose(serialize = false)
    @Until()
    private String mID = null;

    @GsonUtil.ICustomIgnoreAnnotation
    public long mobilePhone = ;

    public Person(){

    }

    public void setName(String name){
        this.mName = name;
    }

    public void setAge(int age){
        this.mAge = age;
    }

    public void setAddress(String address){
        this.mAddress = address;
    }

    public void setSchool(String school){
        this.mSchool = school;
    }

    public void setID(String id){
        this.mID = id;
    }

    public String getName(){
        return mName;
    }

    public int getAge(){
        return this.mAge;
    }

    public String getAddress(){
        return this.mAddress;
    }

    public String getSchool(){
        return this.mAddress;
    }

    public String getID(){
        return this.mID;
    }
}
           

現在用以下代碼進行測試:

代碼、
 Person person = new Person();
        person.setName("bobo");
        person.setAddress("zhuhai");
        person.setAge();
        person.setSchool("華中科技大學");
        person.setID("123456");

        mGson = new GsonBuilder()
                .excludeFieldsWithoutExposeAnnotation()
                .serializeNulls().setExclusionStrategies()
                .enableComplexMapKeySerialization() .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
                .create();
        Type typeOfT = new TypeToken<Person>(){}.getType(); /
        String strPer = mGson.toJson(person, typeOfT);

 輸出結果:
 strPer = {"m_name":"bobo","m_age":}
 Person中隻有m_name ,m_age設定了可序列化,是以經過excludeFieldsWithoutExposeAnnotation的篩選之後導出資料隻有這個屬性,因為屬性命名規則為LOWER_CASE_WITH_UNDERSCORES,是以大寫字母的以下劃線分開,并且大寫轉小寫。
           

(7)、自定義序列化篩選。僅僅采用excludeFieldsWithoutExposeAnnotation對序列化的屬性進行實作有時候會讓代碼特别難看,例如類中有20個屬性,如果每個屬性上都增加expse注解,則代碼看起來非常紮亂,這個時候自定義ExclusionStrategy 就派上了用場,通過實作ExclusionStrategy 的2個篩選方法,可以選擇性的去篩選掉指定的屬性或類。

一、自定義一個注解。
    代碼:
    /**自定義注解,注解頂層帶的注解是固定必須的(可以參考Expose結構)
     *
     */
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.FIELD})
    public @interface ICustomIgnoreAnnotation{}

二、自定義排除政策。
    代碼:
    /**自定義排除政策
     *
     */

    public static class CustomExclusionStrategies implements ExclusionStrategy {
        Class<?> mExClass = null;

        public CustomExclusionStrategies(Class<?> exClass){
            mExClass = exClass;
        }

        @Override
        public boolean shouldSkipField(FieldAttributes fieldAttributes) {
            Collection<Annotation> annotations = fieldAttributes.getAnnotations();
            for (Annotation annotation : annotations){
                if (annotation.annotationType() == ICustomIgnoreAnnotation.class){
                    return true;
                }
            }
            return false;
        }

        @Override
        public boolean shouldSkipClass(Class<?> aClass) {
            return false;
        }
    }
    ExclusionStrategy 借口中有個方法shouldSkipField、shouldSkipClass,分别是對類和屬性進行篩選。
    請檢視shouldSkipField的實作,如果傳入的屬性增加了注解ICustomIgnoreAnnotation則不對其序列化。

三、自定義注解和篩選政策已經寫好,那麼可以通過以下代碼進行引用。
           
Person person = new Person();
    person.setName("bobo");
    person.setAddress("zhuhai");
    person.setAge(30);
    person.setSchool("華中科技大學");
    person.setID("123456");
    Type typeOfT = new TypeToken<Person>(){}.getType(); 
    CustomExclusionStrategies customExclusionStrategies = new CustomExclusionStrategies(person.getClass());
    mGson = new GsonBuilder()
            .setExclusionStrategies(customExclusionStrategies) 
            .serializeNulls().setExclusionStrategies()
            .enableComplexMapKeySerialization() 
            .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
            .create();
    strPer = mGson.toJson(person, typeOfT);

    輸出結果為:{"m_name":"bobo","m_age":30,"m_address":"zhuhai","m_school":"華中科技大學","iD":"123456"}
    因為隻有屬性mobilePhone設定了自定義的注解ICustomIgnoreAnnotation,根據篩選政策,設定了該注解的屬性不會被序列化。
```
           

(8)、解JSON。

現在有一個JSON檔案如下:

{
    "fillType" : "none",
    "height" : ,
    "shapeId" : ,
    "shapeText" : {
        "anchorCenter" : false,
        "paraData" : [{
                "className" : "c11",
                "text" : "生産"
            }, {
                "className" : "c11",
                "text" : "\n需要"
            }
        ],
        "vertical" : false
    },
    "width" : ,
    "x" : ,
    "y" : 
}
           

現在分别采用兩種方式進行解析:

a、JSONObject、JSONArray進行解析。

//通過JSONObject,JSONArray解析
        try {
            JSONObject jsonObject = new JSONObject(jsonStr);
            String fillType = jsonObject.getString("fillType");
            int x = jsonObject.getInt("x");
            int y = jsonObject.getInt("y");
            double width = jsonObject.getDouble("width");
            double height = jsonObject.getDouble("height");
            int shapeId = jsonObject.getInt("shapeId");
            JSONObject shapeText = jsonObject.getJSONObject("shapeText");
            boolean anchorCenter = jsonObject.getBoolean("anchorCenter");
            boolean vertical = jsonObject.getBoolean("vertical");

            JSONArray paraData = jsonObject.getJSONArray("paraData");
            for (int i = , length = paraData.length(); i < length; i ++){
                JSONObject jsonObject1 = paraData.getJSONObject(i);
                String className = jsonObject1.getString("className");
                String text = jsonObject1.getString("text");
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }
           
b、通過Gson定義Bean進行解析,定義類的屬性名稱一樣要和json檔案的key保持一模一樣。
    根據以json結構,可以定義3個類,分别為ExtractDrawing、ExtractShapeText、ExtractParaData。

    ExtractDrawing.java:
           
public class ExtractDrawing {
    String fillType;
    float x = ;
    float y = ;
    float width = ;
    float height = ;
    int shapeId;
    ExtractShapeText shapeText = null;

    public ExtractDrawing(){
        shapeText = new ExtractShapeText();
    }

}
           
ExtractShapeText.java:
           
public class ExtractShapeText {
    boolean vertical = false;
    boolean anchorCenter = false;
    List<ExtractParaData> paraData = new ArrayList<>();
}
           
ExtractParaData.java:
           
public class ExtractParaData {
    String className;
    String text;
}
           
執行代碼:
        //按照提供的字元串結構,自定義一些類,然後通過傳入class來進行解析
        Gson gson = new Gson();
        ExtractDrawing extractDrawing = gson.fromJson(jsonStr, ExtractDrawing.class);

    輸出結果:
    ![輸出結果]:
    ![這裡寫圖檔描述](http://img.blog.csdn.net/?watermark//text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvd2FuZ3FpdWJvMjAxMA==/font/a6L5L2T/fontsize//fill/I0JBQkFCMA==/dissolve//gravity/SouthEast)
           

3、fastJson是阿裡巴巴突出的一款開源基于JAVA的一種Json解析庫,是目前最常用JSON解析方法中最高效,也是最簡單的。fastJson已經封裝好了ExclusionStrategy ,隻需要簡單設定,可以解決大部分的功能,是以推薦首選fastJson。

(1)、fastJson預設情況下,序列化對象,則不會序列化的有一下幾種:靜态方法或者屬性,private和protected定義的屬性或者方法,setXXX(set開頭的方法),傳回值為null的不會被序列化(需要序列化需要配置SerializerFeature)。是以預設情況下,fastJson隻會序列化公有非靜态的方法或者屬性,并且set開頭的方法不會被序列化,get方法開頭的會去掉get并且get之後的第一個字母會轉成小寫, 例如:segName(){},本方法不會被序列化,getName(){},序列化的key為name。
(2)、fastJson注解,fastJson注解主要用到JSONField,本注解名字雖然是作用于屬性,其實他的目标有三個,屬性、方法及其參數,看源代碼就可以發現@Target({ ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER })。
   本注解有ordinal(指定排列順序,預設為0),name(命名),format(格式)、serialize(是否序列化預設為true),deserialize(是否反序列化,預設true),serialzeFeatures(SerializerFeature[]),parseFeatures(Feature[])。
(3)、如果類中屬性也是公有的,本屬性的傳回方法也是有公有的,那麼如果讓序列化的對象隻保留一份,則就可以在屬性或者傳回方法寫上注解@JSONField[serialize=false].
(4)、NameFilter,ValueFilter通過key或者vale進行過濾。
(5)、SerializerFeature最常用的進行說明:
 SerializerFeature.DisableCircularReferenceDetect消除對象之間的循環引用,例如 A引用了B,而B同也引用了A。
 SerializerFeature.WriteMapNullValue,預設情況下如果map為null是不會序列化輸出的,如果需要輸出則配置本值,輸出值為null。
 SerializerFeature.WriteNullListAsEmpty,預設情況下清單為null是不會序列化輸出的,如果需要輸出增加本配置就可以了,輸出為空。
 SerializerFeature.WriteNullStringAsEmpty,預設情況下String類型的序列化屬性或者方法為null時不序列化輸出,如果需要輸出配置本值。
 SerializerFeature.WriteNullNumberAsZero,如果數字類型的為null,預設情況下不序列化輸出,如果需要輸出配置本屬性會給一個預設值0。
 SerializerFeature.WriteNullBooleanAsFalse,Boolean對象為null則預設不會序列化輸出,如果需要輸出配置本屬性預設給一個false。
           

貼上以下代碼提供參考:

public static String fastJsonEncoder(Object object){
        Person person = new Person();
        person.setName("bobo");
        person.setAddress("zhuhai");
        person.setAge();
        person.setSchool("華中科技大學");
        person.setID("123456");

        NameFilter nameFilter = new NameFilter() {
            Pattern pattern = Pattern.compile("[0-9]*");
            //正規表達式判定定ke是否為數字
            public boolean isIndex(String str) {
                Matcher isNum = pattern.matcher(str);
                return isNum.matches();
            }
            /**
             *
             * @param o
             * @param propertyName
             * @param propertyValue
             * @return 擷取到的為key,如果要修改key的值,則在process處理後傳回的就是修改之後的key的值
             */
            @Override
            public String process(Object o, String propertyName, Object propertyValue) {
                //propertyName,序列化後的每個key,propertyValue序列化後的每個key的value
                return propertyName;
            }
        };



        ValueFilter valueFilter = new ValueFilter() {
            /**
             *
             * @param o
             * @param propertyName
             * @param propertyValue
             * @return 傳回的是修改後的value的值,如果需要修改某個key對應的value的值,則在processc處理之後傳回的值即是修改的value的值
             */
            @Override
            public Object process(Object o, String propertyName, Object propertyValue) {

                //propertyName,序列化後的每個key,propertyValue序列化後的每個key的value
                if (propertyName.equals("bobo"))
                    return new String("13633333333");
                else
                    return null;
            }
        };
        return JSON.toJSONString(person, nameFilter,  SerializerFeature.DisableCircularReferenceDetect);
    }