写点什么

Android Gson 使用详解,flutterlistview 动态配置

作者:嘟嘟侠客
  • 2021 年 11 月 27 日
  • 本文字数:7122 字

    阅读完需:约 23 分钟

//通过构造函数来获取 Gson gson = new Gson();//通过 GsonBuilder 来获取,可以进行多项特殊配置 Gson gson = new GsonBuilder().create();

1.2、生成 Json

利用 Gson 可以很方便地生成 Json 字符串,通过使用 addProperty 的四个重载方法


public static void main(String[] args) {JsonObject jsonObject = new JsonObject();jsonObject.addProperty("String", "leavesC");jsonObject.addProperty("Number_Integer", 23);jsonObject.addProperty("Number_Double", 22.9);jsonObject.addProperty("Boolean", true);jsonObject.addProperty("Char", 'c');System.out.println();System.out.println(jsonObject);}



addProperty 方法底层调用的是 add(String property, JsonElement value) 方法,即将基本数据类型转化为了 JsonElement 对象,JsonElement 是一个抽象类,而 JsonObject 继承了 JsonElement ,因此我们可以通过 JsonObject 自己来构建一个 JsonElement


public static void main(String[] args) {JsonObject jsonObject = new JsonObject();jsonObject.addProperty("String", "leavesC");jsonObject.addProperty("Number", 23);jsonObject.addProperty("Number", 22.9);jsonObject.addProperty("Boolean", true);jsonObject.addProperty("Char", 'c');


JsonObject jsonElement = new JsonObject();jsonElement.addProperty("Boolean", false);jsonElement.addProperty("Double", 25.9);jsonElement.addProperty("Char", 'c');jsonObject.add("JsonElement", jsonElement);


System.out.println();System.out.println(jsonObject);}


1.3、Json 与数组、List 的转化

Json 数组 与 字符串数组


public static void main(String[] args) {//Json 数组 转为 字符串数组 Gson gson = new Gson();String jsonArray = "["https://github.com/leavesC","https://www.jianshu.com/u/9df45b87cfdf","Java","Kotlin","Git","GitHub"]";String[] strings = gson.fromJson(jsonArray, String[].class);System.out.println("Json 数组 转为 字符串数组: ");for (String string : strings) {System.out.println(string);}//字符串数组 转为 Json 数组 jsonArray = gson.toJson(jsonArray, new TypeToken<String>() {}.getType());System.out.println("\n 字符串数组 转为 Json 数组: ");System.out.println(jsonArray);}



Json 数组 与 List


public static void main(String[] args) {//Json 数组 转为 ListGson gson = new Gson();String jsonArray = "["https://github.com/leavesC","https://www.jianshu.com/u/9df45b87cfdf","Java","Kotlin","Git","GitHub"]";List<String> stringList = gson.fromJson(jsonArray, new TypeToken<List<String>>() {}.getType());System.out.println("\nJson 数组 转为 List: ");for (String string : stringList) {System.out.println(string);}//List 转为 Json 数组 jsonArray = gson.toJson(stringList, new TypeToken<List<String>>() {}.getType());System.out.println("\nList 转为 Json 数组: ");System.out.println(jsonArray);}


1.4、序列化与反序列化

Gson 也提供了 toJson()fromJson() 两个方法用于转化 Model 与 Json,前者实现了序列化,后者实现了反序列化 首先,声明一个 User 类


/**


  • 作者:chenZY

  • 时间:2018/3/17 18:32

  • 描述:https://github.com/leavesC*/public class User {


private String name;


private int age;


private boolean sex;


public User(String name, int age, boolean sex) {this.name = name;this.age = age;this.sex = sex;}


@Overridepublic String toString() {return "User{" +"name='" + name + ''' +", age=" + age +", sex=" + sex +'}';}


}


序列化的方法很简单,调用 gson 对象的 toJson 方法,传入要序列化的对象


public static void main(String[] args) {//序列化 User user = new User("leavesC", 24, true);Gson gson = new Gson();System.out.println();System.out.println(gson.toJson(user));}



反序化的方式也类似


public static void main(String[] args) {//反序列化 String userJson = "{"name":"leavesC","age":24,"sex":true}";Gson gson = new Gson();User user = gson.fromJson(userJson, User.class);System.out.println();System.out.println(user);}

二、属性重命名

继续使用上一节声明的 User 类,根据 User 类声明的各个属性名,移动端的开发者希望接口返回的数据格式即是如下这样的


{"name":"leavesC","age":24,"sex":true}


如果没有和服务器端沟通好或者是 API 改版了,接口返回的数据格式可能是这样的


{"Name":"leavesC","age":24,"sex":true}


{"userName":"leavesC","age":24,"sex":true}


如果继续使用上一节介绍的方法,那无疑会解析出错 例如


public static void main(String[] args) {//反序列化 String userJson = "{"userName":"leavesC","age":24,"sex":true}";Gson gson = new Gson();User user = gson.fromJson(userJson, User.class);System.out.println();System.out.println(user);}


name 属性值解析不到,所以为 null



此时为了兼顾多种格式的数据,就需要使用 SerializedName 注解 根据 SerializedName 的声明来看,SerializedName 包含两个属性值,一个是字符串,一个是字符串数组,而字符串数组含有默认值


@Documented@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.FIELD, ElementType.METHOD})public @interface SerializedName {String value();


String[] alternate() default {};}


SerializedName 的作用是为了在序列化或反序列化时,指导 Gson 如果将原有的属性名和其它特殊情况下的属性名联系起来


例如,修改 User 类,为 name 声明 SerializedName 注解,注解值为 userName


/**


  • 作者:chenZY

  • 时间:2018/3/17 18:32

  • 描述:https://github.com/leavesC*/public class User {


@SerializedName("userName")private String name;


private int age;


private boolean sex;


}


在序列时,Json 格式就会相应改变


public static void main(String[] args) {//序列化 User user = new User("leavesC", 24, true);Gson gson = new Gson();System.out.println();System.out.println(gson.toJson(user));}



在反序列化时也一样,能够解析到正确的属性值


public static void main(String[] args) {//反序列化 String userJson = "{"userName":"leavesC","age":24,"sex":true}";Gson gson = new Gson();User user = gson.fromJson(userJson, User.class);System.out.println();System.out.println(user);}



还有个问题没解决,为了应对多种属性名不一致的情况,难道我们要声明多个 User 类吗?这显然是不现实的,所以还需要为 User 类设置多个备选属性名,这就需要用到 SerializedName 注解的另一个属性值 alternate 了。


/**


  • 作者:chenZY

  • 时间:2018/3/17 18:32

  • 描述:https://github.com/leavesC*/public class User {


@SerializedName(value = "userName", alternate = {"user_name", "Name"})private String name;


private int age;


private boolean sex;


}


以下几种情况都能够被正确的反序列化


public static void main(String[] args) {//反序列化 Gson gson = new Gson();String userJson = "{"userName":"leavesC","age":24,"sex":true}";User user = gson.fromJson(userJson, User.class);System.out.println();System.out.println(user);


userJson = "{"user_name":"leavesC","age":24,"sex":true}";user = gson.fromJson(userJson, User.class);System.out.println();System.out.println(user);


userJson = "{"Name":"leavesC","age":24,"sex":true}";user = gson.fromJson(userJson, User.class);System.out.println();System.out.println(user);}


三、字段过滤

有时候并不是所有的字段都需要进行系列化和反序列化,因此需要对某些字段进行排除,有四种方法可以来实现这种需求。

3.1、基于 @Expose 注解

Expose 注解包含两个属性值,且均声明了默认值。Expose 的含义即为“暴露”,即用于对外暴露字段,serialize 用于指定是否进行序列化,deserialize 用于指定是否进行反序列化。如果字段不声明 Expose 注解,则意味着不进行序列化和反序列化操作,相当于两个属性值均为 false 。此外,Expose 注解需要和 GsonBuilder 构建的 Gson 对象一起使用才能生效。


@Documented@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.FIELD})public @interface Expose {boolean serialize() default true;


boolean deserialize() default true;}


Expose 注解的注解值声明情况有四种


@Expose(serialize = true, deserialize = true) //序列化和反序列化都生效 @Expose(serialize = false, deserialize = true) //序列化时不生效,反序列化时生效 @Expose(serialize = true, deserialize = false) //序列化时生效,反序列


《Android 学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》

【docs.qq.com/doc/DSkNLaERkbnFoS0ZF】 完整内容开源分享


化时不生效 @Expose(serialize = false, deserialize = false) //序列化和反序列化都不生效,和不写注解一样


现在来看个例子,修改 User 类


/**


  • 作者:chenZY

  • 时间:2018/3/17 18:32

  • 描述:https://github.com/leavesC*/public class User {


@Expose(serialize = true, deserialize = true) //序列化和反序列化都生效 private String a;


@Expose(serialize = false, deserialize = true) //序列化时不生效,反序列化时生效 private String b;


@Expose(serialize = true, deserialize = false) //序列化时生效,反序列化时不生效 private String c;


@Expose(serialize = false, deserialize = false) //序列化和反序列化都不生效,和不写注解一样 private String d;


private String e;


public User(String a, String b, String c, String d, String e) {this.a = a;this.b = b;this.c = c;this.d = d;this.e = e;}


@Overridepublic String toString() {return "User{" +"a='" + a + ''' +", b='" + b + ''' +", c='" + c + ''' +", d='" + d + ''' +", e='" + e + ''' +'}';}


}


按照如上的注解值,只有声明了 Expose 注解且 serialize 值为 true 的字段才能被序列化,只有声明了 Expose 注解且 deserialize 值为 true 的字段才能被反序列化


public static void main(String[] args) {Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();User user = new User("A", "B", "C", "D", "E");System.out.println();System.out.println(gson.toJson(user));


String json = "{"a":"A","b":"B","c":"C","d":"D","e":"E"}";user = gson.fromJson(json, User.class);System.out.println();System.out.println(user.toString());}


3.2、基于版本

Gson 提供了 @Since 和 @Until 两个注解基于版本对字段进行过滤,@Since 和 @Until 都包含一个 Double 属性值,用于设置版本号。Since 的意思是“自……开始”,Until 的意思是“到……为止”,一样要和 GsonBuilder 配合使用。


@Documented@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.FIELD, ElementType.TYPE})public @interface Since {double value();}


@Documented@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.FIELD, ElementType.TYPE})public @interface Until {double value();}


当版本( GsonBuilder 设置的版本) 大于或等于 Since 属性值或小于 Until 属性值时字段会进行序列化和反序列化操作,而没有声明注解的字段都会加入序列化和反序列操作


现在来看个例子,修改 User 类


/**


  • 作者:chenZY

  • 时间:2018/3/17 18:32

  • 描述:https://github.com/leavesC*/public class User {


@Since(1.4)private String a;


@Since(1.6)private String b;


@Since(1.8)private String c;


@Until(1.6)private String d;


@Until(2.0)private String e;


public User(String a, String b, String c, String d, String e) {this.a = a;this.b = b;this.c = c;this.d = d;this.e = e;}


@Overridepublic String toString() {return "User{" +"a='" + a + ''' +", b='" + b + ''' +", c='" + c + ''' +", d='" + d + ''' +", e='" + e + ''' +'}';}


}


public static void main(String[] args) {Gson gson = new GsonBuilder().setVersion(1.6).create();User user = new User("A", "B", "C", "D", "E");System.out.println();System.out.println(gson.toJson(user));


String json = "{"a":"A","b":"B","c":"C","d":"D","e":"E"}";user = gson.fromJson(json, User.class);System.out.println();System.out.println(user.toString());}


3.3、基于访问修饰符

访问修饰符由 java.lang.reflect.Modifier 提供 int 类型的定义,而 GsonBuilder 对象的 excludeFieldsWithModifiers方法接收一个 int 类型可变参数,指定不进行序列化和反序列化操作的访问修饰符字段 看个例子


/**


  • 作者:chenZY

  • 时间:2018/3/17 18:32

  • 描述:https://github.com/leavesC*/public class ModifierSample {


public String publicField = "public";


protected String protectedField = "protected";


private String privateField = "private";


String defaultField = "default";


final String finalField = "final";


static String staticField = "static";


}


public static void main(String[] args) {Gson gson = new GsonBuilder().excludeFieldsWithModifiers(Modifier.PRIVATE, Modifier.STATIC).create();ModifierSample modifierSample = new ModifierSample();System.out.println(gson.toJson(modifierSample));}


3.4、基于策略

GsonBuilder 类包含 setExclusionStrategies(ExclusionStrategy... strategies)方法用于传入不定长参数的策略方法,用于直接排除指定字段名或者指定字段类型 看个例子


/**


  • 作者:chenZY

  • 时间:2018/3/17 18:32

  • 描述:https://github.com/leavesC*/public class Strategies {


private String stringField;


private int intField;


private double doubleField;


public Strategies(String stringField, int intField, double doubleField) {this.stringField = stringField;this.intField = intField;this.doubleField = doubleField;}


@Overridepublic String toString() {return "Strategies{" +"stringField='" + stringField + ''' +", intField=" + intField +", doubleField=" + doubleField +'}';}


}


public static void main(String[] args) {Gson gson = new GsonBuilder().setExclusionStrategies(new ExclusionStrategy() {@Overridepublic boolean shouldSkipField(FieldAttributes fieldAttributes) {//排除指定字段名 return fieldAttributes.getName().equals("intField");}


@Overridepublic boolean shouldSkipClass(Class<?> aClass) {//排除指定字段类型 return aClass.getName().equals(double.class.getName());}}).create();


Strategies strategies = new Strategies("stringField", 111, 11.22);System.out.println();System.out.println(gson.toJson(strategies));


String json = "{"stringField":"stringField","intField":111,"doubleField":11.22}";strategies = gson.fromJson(json, Strategies.class);System.out.println();System.out.println(strategies);}


字段名为 "intField" 和字段类型为 double 的字段都会被排除掉



setExclusionStrategies 方法在序列化和反序列化时都会生效,如果只是想指定其中一种情况下的排除策略或分别指定排除策略,可以改为使用以下两个方法


addSerializationExclusionStrategy(ExclusionStrategy strategy);


addDeserializationExclusionStrategy(ExclusionStrategy strategy);

四、个性化配置

4.1、输出 null

对于 Gson 而言,在序列化时如果某个属性值为 null 的话,那么在序列化时该字段不会参与进来,如果想要显示输出该字段的话,可以通过 GsonBuilder 进行配置


/**


  • 作者:chenZY

  • 时间:2018/3/17 18:32

  • 描述:https://github.com/leavesC*/public class Strategies {


private String stringField;


private int intField;


private double doubleField;


}


public static void main(String[] args) {Gson gson = new GsonBuilder().serializeNulls() //输出 null.create();Strategies strategies = new Strategies(null, 24, 22.333);System.out.println();System.out.println(gson.toJson(strategies));}


4.2、格式化输出 Json

默认的序列化后的 Josn 字符串并不太直观,可以选择格式化输出


public static void main(String[] args) {Gson gson = new GsonBuilder().serializeNulls() //输出 null.setPrettyPrinting()//格式化输出.create();

写在最后

由于本文罗列的知识点是根据我自身总结出来的,并且由于本人水平有限,无法全部提及,欢迎大神们能补充~


将来我会对上面的知识点一个一个深入学习,也希望有童鞋跟我一起学习,一起进阶。


提升架构认知不是一蹴而就的,它离不开刻意学习和思考。


**这里,笔者分享一份从架构哲学的层面来剖析的视频及资料分享给大家,**梳理了多年的架构经验,筹备近 1 个月最新录制的,相信这份视频能给你带来不一样的启发、收获。




最近还在整理并复习一些 Android 基础知识点,有问题希望大家够指出,谢谢。


希望读到这的您能转发分享和关注一下我,以后还会更新技术干货,谢谢您的支持!


转发+点赞+关注,第一时间获取最新知识点


Android 架构师之路很漫长,一起共勉吧!


本文已被CODING开源项目:《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》收录

用户头像

嘟嘟侠客

关注

还未添加个人签名 2021.03.19 加入

还未添加个人简介

评论

发布
暂无评论
Android Gson使用详解,flutterlistview动态配置