android gson的使用

项目中一直使用的原生解析JSONObject.
参考链接https://www.jianshu.com/p/e740196225a4#
基于Gson V2.8.5

序列化: 把Java对象转换为字节序列的过程。 eg:toJson(对象)
反序列化:把字节序列恢复为Java对象的过程。eg:fromJson("字节序列",对象)

Gson基本用法

  • toJson序列化.
public String toJson(Object src) {
public String toJson(Object src, Type typeOfSrc) {}
public void toJson(Object src, Appendable writer) throws JsonIOException {}
public void toJson(Object src, Type typeOfSrc, Appendable writer) throws JsonIOException {}
public void toJson(Object src, Type typeOfSrc, JsonWriter writer) throws JsonIOException {}
public String toJson(JsonElement jsonElement) {}
public void toJson(JsonElement jsonElement, Appendable writer) throws JsonIOException {}
public void toJson(JsonElement jsonElement, JsonWriter writer) throws JsonIOException {}
  • fromJson反序列化.
public <T> T fromJson(String json, Class<T> classOfT) throws JsonSyntaxException {}
public <T> T fromJson(String json, Type typeOfT) throws JsonSyntaxException {}
public <T> T fromJson(Reader json, Class<T> classOfT) throws JsonSyntaxException, JsonIOException {}
public <T> T fromJson(Reader json, Type typeOfT) throws JsonIOException, JsonSyntaxException {}
public <T> T fromJson(JsonReader reader, Type typeOfT) throws JsonIOException, JsonSyntaxException {}
public <T> T fromJson(JsonElement json, Class<T> classOfT) throws JsonSyntaxException {}
public <T> T fromJson(JsonElement json, Type typeOfT) throws JsonSyntaxException {}

基本数据类型的生成、

        Gson gson=new Gson();
        String jsonString=gson.toJson("java");//java
        String jsonNumber=gson.toJson(2018);//2018
        String jsonBoolean=gson.toJson(true);//true

POJO类的生成与解析普通java类

String jsonResponse="{
    "code": 200,
    "msg": "OK",
    "user": [
        {
            "name": "cqx1",
            "age": "2018",
            "phone": "166...111",
            "email": "183xxxx111@qq.com"
        },
        {
            "name": "cqx2",
            "age": "2018",
            "phone": "166...222",
            "email": "183xxxx222@qq.com"
        }
    ]
}";

  private class StudentEntity {
        private String code;
        @Expose
        private String msg;
        /**
         * 此处user为json串的key,下面的userList为自己定义的别名
         */
        @SerializedName("user")
        private List<UserEntity> userList;

  private class UserEntity {
        private String name;
        private String age;
        private String phone;
        private String emails;
        ...

如果此时按照以下解析,哪怕try catch也拦截不到。

 /**
     * 从raw包下读取数据
     * @param context
     * @param rawName   R.raw.cqx
     * @return
     */
    public static String getFileStremFromRaw(Activity context, int rawName) {
        try {
            InputStreamReader inputReader = new InputStreamReader(context.getResources().openRawResource(rawName));
            BufferedReader bufReader = new BufferedReader(inputReader);
            String line = "";
            String Result = "";
            while ((line = bufReader.readLine()) != null)
                Result += line;
            return Result;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }
    

解析上面的报文。

 private void parseJsonReponse() {
        String response = FileTools.getFileStremFromRaw(this, R.raw.test);
        JsonParser jsonParser = new JsonParser();
        JsonObject jsonObject = jsonParser.parse(response).getAsJsonObject();
        try {

//因为对应的为Object,所以这样的解析就会异常崩溃,并且拦截无用。
            JsonArray jsonArray = jsonParser.parse(response).getAsJsonArray();
        } catch (JsonSyntaxException e) {
            e.printStackTrace();
        }
        String msg=jsonObject.get("msg").getAsString();
    }

错误日志如下:

     Caused by: java.lang.IllegalStateException: Not a JSON Array: {"code":200,"msg":"OK","user":[{"name":"cqx1","age":"2018","phone":"166...111","email":"183xxxx111@qq.com"},{"name":"cqx2","age":"2018","phone":"166...222","email":"183xxxx222@qq.com"}]}
        at com.google.gson.JsonElement.getAsJsonArray(JsonElement.java:107)
        at com.cc.rxjava.gson.GsonActivity.parseJsonReponse(GsonActivity.java:76)
        at com.cc.rxjava.gson.GsonActivity.onCreate(GsonActivity.java:68)
        at android.app.Activity.performCreate(Activity.java:6715)

然后实际开发中,后台返回的json格式可能跟我们要的不一致,如果线上的因为后台返回的数据格式而崩溃,哪怕最终查出原因是后台的问题,最终客户端还是得背锅,谁叫没有做容错处理呢。
如果服务端返回的为正确的数据解析方式:

    private void parseJsonReponse() {
        String response = FileTools.getFileStremFromRaw(this, R.raw.test);
        StudentEntity studentEntity = new Gson().fromJson(response, StudentEntity.class);
        Type type =new TypeToken<StudentEntity>(){}.getType();
        StudentEntity studentEntity2 = new Gson().fromJson(response, type);
//        userList = studentEntity.userList;
    }

json的生成

将对象转换为字节序列的过程。toJson

  Gson gson = new Gson();
  UserEntity user = new UserEntity("cc","2018","1660....","183...@qq.com");
  String jsonObject = gson.toJson(user);//{"age":"2018","emails":"183...@qq.com","name":"cc","phone":"1660...."}

解析Json

将字节系列转为为对象的过程。fromJson

UserEntity userEntity = gson.fromJson(jsonObject, UserEntity.class);

List<UserEntity> list = gson.fromJson(jsonArray, new TypeToken<List<UserEntity>>() {
        }.getType());

数组

String[] strings = gson.fromJson(jsonArray, String[].class);

List

 List<String> stringList = gson.fromJson(jsonArray, new TypeToken<List<String>>() {}.getType());

@Expose、@SerializeName注解

json解析的字段(key)的名称和类型是一一对应的,当客户端和后台使用的语言不同,二者语言命名规范不同,命名规则常常不统一的情况下,使用@Expose和@SerializeName注解。
@Expose注解:区分实体中序列号的属性,包含两个属性,deserialize(反序列化)和serialize(序列化),默认为true。使用@Expose进行序列化,如果不想被序列化也可以使用transient。

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Expose {
  
  /**
   * If {@code true}, the field marked with this annotation is written out in the JSON while
   * serializing. If {@code false}, the field marked with this annotation is skipped from the
   * serialized output. Defaults to {@code true}.
   * @since 1.4
   */
  public boolean serialize() default true;

  /**
   * If {@code true}, the field marked with this annotation is deserialized from the JSON.
   * If {@code false}, the field marked with this annotation is skipped during deserialization. 
   * Defaults to {@code true}.
   * @since 1.4
   */
  public boolean deserialize() default true;
}

@SerializeName注解:属性重命名

//使用这样的方式创建gson对象。
Gson gson=new Gson().newBuilder().excludeFieldsWithoutExposeAnnotation().create();
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD})
public @interface SerializedName {

  /**
   * @return the desired name of the field when it is serialized or deserialized
   */
  String value();
  /**
   * @return the alternative names of the field when it is deserialized
   */
  String[] alternate() default {};
}

用例

@SerializedName("email_address")
public String emailAddress;

如果存在一个key多个写法,则可以选择@SerializeName的alternate别名的选择,根据以上代码可知为一个字符串数组。

借用例子
{"name":"怪盗kidou","age":24,"emailAddress":"ikidou@example.com"}
{"name":"怪盗kidou","age":24,"email_address":"ikidou@example.com"}
{"name":"怪盗kidou","age":24,"email":"ikidou@example.com"}
作者:怪盗kidou
链接:https://www.jianshu.com/p/e740196225a4#

所以处理办法是:

@SerializedName(value = "emailAddress", alternate = {"email", "email_address"})
public String emailAddress;

多个情况同时存在时:
Gson gson = new Gson();
String json = "{\"name\":\"怪盗kidou\",\"age\":24,\"emailAddress\":\"ikidou_1@example.com\",\"email\":\"ikidou_2@example.com\",\"email_address\":\"ikidou_3@example.com\"}";
User user = gson.fromJson(json, User.class);
System.out.println(user.emailAddress); // ikidou_3@example.com

作者:怪盗kidou
链接:https://www.jianshu.com/p/e740196225a4#

补充demo

image.png


如上图可以看到该json格式为外层JsonObject,里面有个key为rltInfo的JsonObject,rltInfo里面存在两个JsonArray的数组list.可以简易封装一下解析:

//基类
public class BaseResult<T> {
    public boolean rltFlag;
    public RltInfoEntity<T> rltInfo;

}

public class RltInfoEntity<T> {
    public String status;
    public String statusDesc;
    @SerializedName("taskList")
    public List<T> mGcTaskList;
//mShTaskList客户端命名规则,shTaskList为服务端返回来的json的key
    @SerializedName("shTaskList")
    public List<T> mShTaskList;
}

/**
 * created by cheng.qx on 2018/8/20 17:10
 */
public class XJTaskEntity {
    /**
     * 任务ID
     */
    private String taskId;

    /**
     * 任务名称
     */
    private String taskName;

    /**
     * 所属用户ID
     */
    private String personId;

    /**
     * 所属用户名称
     */
    private String personName;

    /**
     * 门店ID
     */
    private String storeId;

    /**
     * 门店名称
     */
    @SerializedName("orgName")
    private String storeName;

    /**
     * 区域ID
     */
    private String areaId;

    /**
     * 区域名称
     */
    private String areaName;

    /**
     * 任务开始时间-天
     */
    @SerializedName(value ="beginTimeStr",alternate={"submitTimeStr"})
    private String taskBeginDay;

    /**
     * 任务开始时间-时分秒
     */
    private String taskBeginHour;

    /**
     * 任务结束时间-天
     */
    @SerializedName("endTimeStr")
    private String taskEndDay;

    /**
     * 任务结束时间-时分秒
     */
    private String taskEndHour;

在Activity中解析数据:

   private void initParseToDoList() {
        try {
            String response = FileTools.getFileStremFromRaw(activityContext, R.raw.done_gson);
            Gson gson = new Gson();
            Type type = new TypeToken<BaseResult<XJTaskEntity>>() {
            }.getType();
            BaseResult<XJTaskEntity> baseResult = gson.fromJson(response, type);
            if (baseResult.rltInfo.mGcTaskList != null) {
                taskList.addAll(baseResult.rltInfo.mGcTaskList);
            }
            if (baseResult.rltInfo.mShTaskList != null) {
                taskList.addAll(baseResult.rltInfo.mShTaskList);
            }
            mGsonAdapter.notifyDataSetChanged();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * 从raw包下读取数据
     *
     * @param context
     * @param rawName R.raw.cqx
     * @return
     */
    public static String getFileStremFromRaw(Activity context, int rawName) {
        try {
            InputStreamReader inputReader = new InputStreamReader(context.getResources().openRawResource(rawName));
            BufferedReader bufReader = new BufferedReader(inputReader);
            String line = "";
            String Result = "";
            while ((line = bufReader.readLine()) != null)
                Result += line;
            return Result;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }

Gson解析复杂json的数据。

JsonParse:

通过getAsJsonObjectgetAsJsonArray解析成JsonObject和JsonArray。

JsonElement抽象类。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 225,677评论 6 524
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 96,772评论 3 408
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 173,108评论 0 370
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 61,378评论 1 303
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 70,394评论 6 403
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 53,807评论 1 315
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 42,127评论 3 432
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 41,136评论 0 281
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 47,693评论 1 328
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 39,703评论 3 349
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 41,810评论 1 357
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 37,400评论 5 352
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 43,130评论 3 341
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 33,532评论 0 25
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 34,707评论 1 278
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 50,412评论 3 383
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 46,892评论 2 368

推荐阅读更多精彩内容

  • 1.概述2.Gson的目标3.Gson的性能和扩展性4.Gson的使用者5.如何使用Gson 通过Maven来使用...
    人失格阅读 14,287评论 2 18
  • 【Android 库 Gson】 引用: ★Gson 解析教程★★★ Gson的入门使用Gson全解析(上)-Gs...
    Rtia阅读 2,760评论 0 9
  • Json 是一种文本形式的数据交换格式,比 xml 更为轻量。Json 的解析和生成的方式很多,在 Android...
    业志陈阅读 79,197评论 9 69
  • 以前我对于宠物狗是没有感觉的,因为我家在乡下,家人不允许养任何没有应用价值的动物,所以我只可以看见能装进肚子里的鸡...
    九汝竹书阅读 447评论 5 1
  • 婆媳关系,无论你是家财万贯还是吃了几十年狗粮的单身狗,你都正在或者即将遇到这个问题。这个问题处理好了,鸡犬升天,处...
    炜安Vivian阅读 614评论 0 0