天天看點

Json解析架構之Gson詳解

好東西,大家享

原文來自: http://www.iamxiarui.com/2016/08/30/android

原文作者:iamxiarui

1、簡單的JSON資料進行解析

[
  {
    "name": "zhangsan",
    "age": "10",
    "phone": "11111",
    "email": "[email protected]"
  },
  {
    "name": "lisi",
    "age": "20",
    "phone": "22222",
    "email": "[email protected]"
  },
  ...
]
           

這個是最簡單的一種Json數組格式,Gson可以直接将其解析成一個List。

首先,我們需要建立一個Bean對象,注意變量名要與字段名稱名稱保持一緻。

推薦使用Android Studio 的GsonFormat工具

public class UserBean {
    //變量名跟JSON資料的字段名需要一緻
    private String name ;
    private String age;
    private String phone;
    private String email;
    ...
}
           

之後為解析過程:

/**
 * 解析沒有資料頭的純數組
 */
private void parseNoHeaderJArray() {
    //拿到本地JSON 并轉成String
    String strByJson = JsonToStringUtil.getStringByJson(this, R.raw.juser_1);

    //Json的解析類對象
    JsonParser parser = new JsonParser();
    //将JSON的String 轉成一個JsonArray對象
    JsonArray jsonArray = parser.parse(strByJson).getAsJsonArray();

    Gson gson = new Gson();
    ArrayList<UserBean> userBeanList = new ArrayList<>();

    //加強for循環周遊JsonArray
    for (JsonElement user : jsonArray) {
        //使用GSON,直接轉成Bean對象
        UserBean userBean = gson.fromJson(user, UserBean.class);
        userBeanList.add(userBean);
    }
    mainLView.setAdapter(new UserAdapter(this, userBeanList));
}
           

可以總結出解析步驟為:

①、将網絡請求過來的JSON資料轉換成String類型資料;

②、當JSON内隻有純屬組,用JSON解析類對象将JSON字元串轉為JsonArray;

③、周遊Json數組,使用Gson進行解析。

a、JsonParse:解析類,它可以将Json資料分别通過getAsJsonObject 和 getAsJsonArray 解析成 JsonObject 和JsonArray 。

b、JsonElement:一個抽象類,代表Json字元串内某個元素例如:JsonObject/JsonArray/JsonPrimitive/...

2、有資料頭的純數組資料

Json字元串如下,僅僅在最最簡單的基礎上加了一個約定好的名稱為:"muser" 的資料頭

{
  "muser": [
    {
      "name": "zhangsan",
      "age": "10",
      "phone": "11111",
      "email": "[email protected]"
    },
    {
      "name": "lisi",
      "age": "20",
      "phone": "22222",
      "email": "[email protected]"
    },
    ...
  ]
}
           

使用上面提到的 JsonParse 進行相關操作

/**
 * 解析有資料頭的純數組
 */
private void parseHaveHeaderJArray() {
    //拿到本地JSON 并轉成String
    String strByJson = JsonToStringUtil.getStringByJson(this, R.raw.juser_2);

    //先轉JsonObject
    JsonObject jsonObject = new JsonParser().parse(strByJson).getAsJsonObject();
    //再轉JsonArray 加上資料頭
    JsonArray jsonArray = jsonObject.getAsJsonArray("muser");

    Gson gson = new Gson();
    ArrayList<UserBean> userBeanList = new ArrayList<>();

    //循環周遊
    for (JsonElement user : jsonArray) {
        //通過反射 得到UserBean.class
        UserBean userBean = gson.fromJson(user, new TypeToken<UserBean>() {}.getType());
        userBeanList.add(userBean);
    }
    mainLView.setAdapter(new UserAdapter(this, userBeanList));
}
           

c、TypeToken:為匿名反射類

以下為官方說明:

GSON 提供了 TypeToken 這個類來幫助我們捕獲(capture)像 List 這樣的泛型資訊。Java編譯器會把捕獲到的泛型資訊編譯到這個匿名内部類裡,然後在運作時就可以被 getType() 方法用反射的 API 提取到。
官方要表達的話是:

将泛型 T 轉成 .class 。比如上面的 TypeToken 經過 getType() 後就是UserBean.class 。

對于上面的 JSON 完全可以直接通過 GSON 轉成 List ,不用這麼麻煩,我隻是為了引出3個小知識。

3、有資料頭的複雜資料

Json的字元串如下:

{
  "code": 200,
  "msg": "OK",
  "muser": [
    {
      "name": "zhangsan",
      "age": "10",
      "phone": "11111",
      "email": "[email protected]"
    },
    {
      "name": "lisi",
      "age": "20",
      "phone": "22222",
      "email": "[email protected]"
    },
    ...
  ]
}
           

仔細觀察這個字元串結構發現上面多了兩個字段

"code": 200

"msg": "OK"

首先建立Bean類,這裡再次強調使用Android Studio 的GsonFormat工具

此處省略set/get方法

/**
 * Created by xiarui on 2016/8/30.
 * 傳回所有結果的Bean
 */
public class ResultBean {
    //注意變量名與字段名一緻
    private int code;
    private String msg;
    private List<UserBean> muser;

    public class UserBean{
        private String name ;
        private String age;
        private String phone;
        private String email;
        ...
    }
    ...
}
           
注意:

這個 ResultBean 裡面有一個 UserBean 。 它雖然跟上面第一第二招雖然内容一樣,但是作用不一樣,這是作為 JsonArray 解析後存入List 中的對象。

解析代碼如下:

/**
 * 有消息頭 複雜資料 正常方式
 */
private void parseComplexJArrayByCommon() {
    //拿到Json字元串
    String strByJson = JsonToStringUtil.getStringByJson(this, R.raw.juser_3);
    //GSON直接解析成對象
    ResultBean resultBean = new Gson().fromJson(strByJson,ResultBean.class);
    //對象中拿到集合
    List<ResultBean.UserBean> userBeanList = resultBean.getMuser();
    //展示到UI中
    mainLView.setAdapter(new ResultAdapter(this, userBeanList));
}
           

4、隻解析複雜JSON中的數組或數組中的某部分内容

Json字元串和上面的一樣:

{
  "code": 200,
  "msg": "OK",
  "muser": [
    {
      "name": "zhangsan",
      "age": "10",
      "phone": "11111",
      "email": "[email protected]"
    },
    {
      "name": "lisi",
      "age": "20",
      "phone": "22222",
      "email": "[email protected]"
    },
    ...
  ]
}
           

對于這個問題,不需要一一進行解析,但是有一點需要做的是,需要周遊。

完整代碼解析代碼如下:

/**
 * 有資料頭 複雜資料 截取方式
 */
private void parseComplexJArrayByDirect() {
    //拿到JSON字元串
    String strByJson = JsonToStringUtil.getStringByJson(this, R.raw.juser_3);
    List<UserBean> userBeanList = new ArrayList<>();

    //拿到數組
    JsonObject jsonObject = new JsonParser().parse(strByJson).getAsJsonObject();
    JsonArray jsonArray = jsonObject.getAsJsonArray("muser");

    //循環周遊數組
    for (JsonElement user : jsonArray) {
        UserBean userBean = new Gson().fromJson(user, new TypeToken<UserBean>() {
        }.getType());
        //根據條件過濾
        if (Integer.parseInt(userBean.getAge()) > 30) {
            userBeanList.add(userBean);
        }
    }
    mainLView.setAdapter(new UserAdapter(this, userBeanList));
}
           

5、若Json資料非常非常複雜如下

{
  "group": {
    "user": {
      "name": "張三",
      "age": "10",
      "phone": "11111",
      "email": "[email protected]"
    },
    "info": {
      "address": "北京",
      "work": "Android Dev",
      "pay": "10K",
      "motto": "先定一個小目标,比如我先賺一個億"
    }
  }
}
           

具體解析方式如下(不要問我為啥?我看來的!!!):

/**
 * 通過JsonReader的方式去解析
 */
private void parseComplexJArrayByReader() throws IOException {
    String strByJson = JsonToStringUtil.getStringByJson(this, R.raw.juser_4);
    JsonReader reader = new JsonReader(new StringReader(strByJson));
    try {
        reader.beginObject();
        String tagName = reader.nextName();
        if (tagName.equals("group")) {
            //讀group這個節點
            readGroup(reader);
        }
        reader.endObject();
    } finally {
        reader.close();
    }
}

/**
 * 讀group這個節點
 *
 * @param reader JsonReader
 */
private void readGroup(JsonReader reader) throws IOException {
    reader.beginObject();
    while (reader.hasNext()) {
        String tagName = reader.nextName();
        if (tagName.equals("user")) {
            readUser(reader);
        } else if (tagName.equals("info")) {
            readInfo(reader);
        }
    }
    reader.endObject();
}

/**
 * 讀使用者基本消息 user節點
 *
 * @param reader JsonReader
 */
private void readUser(JsonReader reader) throws IOException {
    reader.beginObject();
    while (reader.hasNext()) {
        String tag = reader.nextName();
        if (tag.equals("name")) {
            String name = reader.nextString();
            nameText.setText(name);
        } else if (tag.equals("age")) {
            String age = reader.nextString();
            ageText.setText(age);
        } 
        ...
        else {
            reader.skipValue();//忽略
        }
    }
    reader.endObject();
}

/**
 * 讀使用者其他消息 info節點
 *
 * @param reader JsonReader
 */
private void readInfo(JsonReader reader) throws IOException {
    reader.beginObject();
    while (reader.hasNext()) {
        String tag = reader.nextName();
        if (tag.equals("address")) {
            String address = reader.nextString();
            addressText.setText(address);
        } else if (tag.equals("work")) {
            String work = reader.nextString();
            workText.setText(work);
        } 
        ...
        else {
            reader.skipValue();//忽略
        }
    }
    reader.endObject();
}