android-gson使用

平时用到也就那么几个方法,花费了时间学的东西用的少就忘记了,捡一捡是时候做做记录了.为了以后复习起来也方便
  1. json是一种格式,用来交换文本形式数据.
  2. 解析json的方式也有很多,框架级的有gson;jackson;fastJson也就够用了
  3. 前两种在google play Top200中使用率57,和15;fastJson没有相关数据,可见gson的比重是相当大的
  4. 下载与使用:github下载地址https://github.com/google/gson
  5. 我是直接将源码拿来放在项目中的,复制gson/gson/src/main/java下的文件放在自己工程的src/main/java下
  6. gson提供了两个直接用于生成和解析json的方法,toJson()实现了序列化,fromjson()实现了反序列化
  7. 这篇文章不错.留个记录点击打开链接
先说说基本用法(不得不贴代码,但是插入代码不够显眼和说明问题,我觉得还是截图吧,有图有真相,所有代码都是我一个个敲出来的,运行在androidstudio上面,所以我敢说,代码绝对跑的通)
  1. 解析基本数据类型--最基本最简单的
    1. 图中可以看见控制台上打出来的已经是把最基本的基本数据类型解析出来了

  2. 生成基本数据类型

  3. 下面做一点稍微复杂点的,简单的java对象,生成与解析
    1. 先写个简单的javabean

    2. 生成json

    3. 可以看见已经通过简单的bean生成了json格式数据
  4. 通过刚才的bean将生成的json数据解析出来

    1. 这个解析也可以通过手动来完成.不过开发中应该没人手动去做,这里就是介绍下

    2. 既然能手动解析json那么能不能手动生成呢?肯定是可以的,看例子

  5. 接下来要说一个注解的使用
    1. 不知道看到这里对上面的例子有没有疑惑?在第一个例子中的double转换时候,有没有发现9.9是字符串?也就是string类型,其实那里应该是这样写的("9.9", double.class);那么为什么写成字符串也可以呢?是因为它有一定的容错机制.但是有时候这个机制并不可行,比如我们把bean在加一个字段emailAddress;这是我们所期望的json应该是
      • {"name":"linzhiling", "age":"33", "email_address":"chen@jt.com"}

但是实际上却是这样的

  • {"name":"linzhiling", "age":"33", "email_address":"chen@jt.com"}

这种情况多出现在不同语言中.如java经常使用emailAddress方式,而php就会是email_address

  • 这时的问题就是到底按照哪种方式?其实是有解决办法的,就是注解@SerializedName
  • 需要做的就是把emailAddress加注解

  • 这样就满足了不同编程语言的要求,也许这时候你想到了,那如果要是再有一种情况怎么办?也有办法
  • 把注解变成数组形式

  • 这样就无论有几种形式就全能搞定了
  • 那么当多种情况同时出现的话,会怎么样呢?我们以注解多种情况为例

  • 是了,是以最后一个为准的.
  • 下面在看一个方法,也是类似上面注解这种,映射规则的GsonBuilder.setFieldNamingPloicy()要配合枚举使用
  • 同样是上面的user类,我们把注解去掉试试下面这样做(GsonBuilder下面会有更多介绍)

  • 是的,key值变了,但是当加上@SerializedName那么就还是原来的样子,说明注解拥有最高的优先级.有注解存在时候这种方式不生效.那么这种枚举类型的有几种呢?答案是五种

  • 除了有系统枚举的实现方式,还可以自定义实现的.

进入下一层次,复杂一点的解析,带有泛型的
  1. 数组的解析,把数组形式的json解析出来

    1. 如果不是数组形式,而是List那应该怎么做呢?直接把String[].class换成List.class是不行的,因为List<String>和List<User>的字节码文件是一样的都是List.class
    2. 现在就要用到泛型了.当我们需要解析List<String>时就要这样做(因为TypeToken的构造方法是protected修饰的所以下面的代码是new TypeToken<List<String>>(){}.getType而不是new TypeToken<List<String>>().getType)

  2. 泛型对bean设计的影响
    1. 可以很大程度的优化代码,比如以下的两种数据类型
      1. {"code":"0", "state":"send","message":{}}
      2. {"code":"0", "state":"send","message":[]}
    2. 发送一条消息的时候,没有异常出现,状态码都是0,状态为发送,仅仅是message不同,这里采用两种数据类型存放message;那么如果message里面需要装多个人的时候应该怎么做呢?定义两个bean吗?比如这样
    3. {}这种形式就用User;[]这种形式就用List<User>是不太好的
    4. 这种做法可以,但是相同的参数却要重复定义多次,这就要用到泛型,下面看看怎么样做会好一些
    5. 定义泛型类
    6. USer类前面已经定义过了直接拿来用
    7. 接下来就是生成两种json的做法

    8. 生成了json然后再看下应该怎么解析.
      1. 假如拿到了json数据,没有使用泛型应该怎么做?是这样的需要创建两个bean

      2. 还是重复定义了,有两个接口还好,要是几十个那可要崩溃了,定义那么多;用泛型就好多了,现在把刚才生成的json解析

      3. 另一种情况的解析

      4. 减少了重复定义,封装性更好,返回值类型更加直观
    9. 使用GsonBuilder,格式化输出,输出null值,时间和日期
      1. 使用方法和例子

      2. 图中例子说明,当需要比较完整的输出,没有值时候需要null这个方法就能用到了
      3. 格式化输出一些信息,从控制台就可以看出区别了
  3. 字段过滤
    1. 字段过滤有这么几种方式:使用注解/不同版本/访问修饰符/自定义策略
    2. 字段过滤的目的是使不想被序列化的字段不被序列化
    3. 下面看一个例子

    4. 不需要序列化就要将这个字段排除.下面就分别介绍几种方法
      1. @Expose注解
        1. 注意这个注解在new Gson()时候是不起作用的,这个注解要想起作用是需要和GsonBuilder配合的
        2. 在需要序列化的字段上加这个注解.是需要序列化的字段
        3. @Expose()有几种用法
          1. @Expose 等价于 @Expose(deserialize = true, serialize = true)//序列化和反序列化都生效
          2. @Expose(deserialize = true, serialize = false)//反序列化生效
          3. @Expose(deserialize = false, serialize = true)//序列化生效
          4. 不加注解 等价于 @Expose(deserialize = false, serialize = false)//不会被序列化
        4. 对于上面的例子就是这样写

          1. 在使用时候要这样new
          2. Gson gson = new GsonBuilder()
                    .excludeFieldsWithoutExposeAnnotation()
                    .create();
                    gson.toJson(people);

      2. 基于版本:Gson在对基于版本的字段导出提供了两个注解:@Since和@Until这两个注解要配合GsonBuilder.setVersion(double)配合使用
        1. class SinceUntilSample {
              @Since(4)
              public String since;
              @Until(5)
              public String until;
          }
          
          public void sineUtilTest(double version){
                  SinceUntilSample sinceUntilSample = new SinceUntilSample();
                  sinceUntilSample.since = "since";
                  sinceUntilSample.until = "until";
                  Gson gson = new GsonBuilder().setVersion(version).create();
                  System.out.println(gson.toJson(sinceUntilSample));
          }
          //当version <4时,结果:{"until":"until"}
          //当version >=4 && version <5时,结果:{"since":"since","until":"until"}
          //当version >=5时,结果:{"since":"since"}


      3. 修饰符都懂了,就是:public static final private protect
        1. class ModifierSample {
              final String finalField = "final";
              static String staticField = "static";
              public String publicField = "public";
              protected String protectedField = "protected";
              String defaultField = "default";
              private String privateField = "private";
          }
          1. 这里要使用GsonBuilder.excludeFieldsWithModifiers创建Gson,所填写的参数就是排除序列化的(使用这个方法的时候有点要注意的地方就是,很可能找不到Modifier,这时候需要手动导包
            import java.lang.reflect.Modifier;)
        2. ModifierSample modifierSample = new ModifierSample();
                  Gson gson = new GsonBuilder()
                  .excludeFieldsWithModifiers(Modifier.FINAL, Modifier.STATIC, Modifier.PRIVATE)
                  .create();
                  System.out.println(gson.toJson(modifierSample));
          // 结果:{"publicField":"public","protectedField":"protected","defaultField":"default"}
      4. 强大的自定义,尤其是android中需要自定义的东西太多了.也体现了自定义的强大
        1. 自定义可以实现按"字段","注解","类"进行排除
        2. 对同样的ModefierSsample,用自定义的方式排除字段

        3. 通过结果可以看出,想要排除的字段已经排除了.那么下面的排除方法什么作用呢?下面把它改成String试试.为了验证可行性,我们同时在ModefierSsample类中多定义一个int字段


        4. 可以看出来除了int的.string全被排除了.这是序列化例子,同样反序列化时候用法是一样的,方法变成
          .addDeserializationExclusionStrategy()
  4. 接下来又是一个重点东西,TypeAdapter,这个是2.0(2.1?)开始提供的一个抽象类,用于接管某种类型的序列化和反序列化过程

包含两个主要方法,writer(JsonWriter, T)和read(JsonReader)其他的方法都是final并最终调用这两个抽象方法

TypeAdapter.JsonSerializer.JsonDeserializer都需要与GsonBuilder.registerTypeAdapter或GsonBuilder.registerTypeHierarchyAdapter配合使用


  1. 通过上面的Adapter来生成json

  2. 当为User.class注册了TypeAdapter之后,只要操作User.class那之前介绍过的@SerializedName,FieldNamingStrategy,Since,Util,这些全都无效

只会调用实现TypeAdapter的UserTypeAdapter.write(JsonWriter, User)这个方法

  • 这里在说一个例子.上文也提到过,Gson是有一定的容错机制的,比如可以将字符串"99"转换成int类型的99,但是如过这里给一个空字符串

怎么办?这时就可以通过注册TypeAdapter把序列化和反序列化的过程接收了.


注意输入的是""字符串.要有转译

  • 这时又有一个问题,假如只想序列化或反序列化可以吗?接下来看另外两个JsonSerializerJsonDeserializer

  1. 可以灵活的只选择序列化或反序列化
  2. 现在修改上面的例子

  3. 再比如将各种数字类型(int, long..只要是数字的)序列化为字符串

    1. 需要注意的是registerTypeAdapter必须使用包装类,所以int.class/long.class/float.class/double.class是不行的;同时这种方式也只能分别注册,不能直接使用Number.class,那么registerTypeAdapter不行有没有可行的呢,那就是换成registerTypeHierarchyAdapter就可以了

    2. 注:registerTypeAdapter支持泛型,不支持继承;registerTypeHierarchyAdapter不支持泛型,支持继承;如果一个被序列化的对象本身就带有泛型,而且注册了相应的TypeAdapter那么必须调用Gson.toJson(Object, Type),明确的告诉Gson对象这个类型

  4. TypeAdapterFactory
    1. 用于创建TypeAdapter的工厂来,通过对比Type确定有没有对应的TypeAdapter,没有就返回null,与GsonBuilder.registerTypeAdapterFactory配合使用
    2. 下面介绍一种用法,这可以随便设置返回值.长用于设置替换null返回值

  5. 另外一个注解:@JsonAdapter;和之前说的几个注解的区别是@JsonAdapter是用在类上面的,而其他的是用在字段上;@JsonAdapter接收一个参数,必须是TypeAdapter,JsonSerializer,JsonDeserializer其中之一;上面说过JsonSerializer,JsonDeserializer都要配合GsonBuilder.registerTypeAdapter使用,每次使用都要注册比较麻烦,@JsonAdapter就解决了这个问题,@JsonAdapter仅支持TypeAdapter或TypeAdapterFactory


    1. 如果注解和GsonBuilder同时存在的话,注解的优先级更高
    2. 到这里基本就结束了.后续如果有新的发现会继续更新

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值