天天看点

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);
    }