Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android之JSON全面解析與使用

Android之JSON全面解析與使用

編輯:關於Android編程

什麼是JSON

JSON 指的是 JavaScript 對象表示法(JavaScript Object Notation) JSON 是輕量級的文本數據交換格式 JSON 獨立於語言 (單純的數據格式,不受語言的約束) JSON 具有自我描述性,更易理解

對於JSON的定義以及數據格式,沒有什麼太多的難點,這裡為官網對JSON的定義。從官網描述中可以看出,JSON本身是JavaScript中對象的描述格式,後來得以推廣並逐漸取代xml。

JSON和XML的比較

相比 XML 的不同之處

沒有結束標簽(類似於鍵值對的形式) 更短(沒有結束標簽,當然短了) 讀寫的速度更快 能夠使用內建的 JavaScript eval() 方法進行解析 使用數組 不使用保留字

原生JSON解析

Android原生的解析實際上使用的JSON的一個官方jar包。對於JSON,不需要頁面展示,所以使用intellij idea進行演示。

在使用之前我們需要下載org.json的jar包。對於Android 開發環境不需要下載此jar包。因為Android SDK 中已經默認包含了該jar包。

json jar 下載地址

下載完之後導入即可。

JSONObject對象解析

下面看一下數據

{
    "user":{
        "name":"alex",
        "age":"18",
        "isMan":true
    }
}

有一個user字段,其中包含了該user的一些基本屬性。那麼如何解析呢?

在解析時,有一個很關鍵的地方:如果是{}包含,則為JSONObject對象,如果為[]則為JSONArray對象。

看到上面的例子,我們看到整個數據為JSONObject,其內部包含了一個user字段,該字段的值也是一個JSONObject對象。

public class OrgJSONTest {

    public static String json = "{\"user\":{\"name\":\"alex\",\"age\":\"18\",\"isMan\":true}}";


    public static void main(String[] args){
        JSONObject obj = new JSONObject(json);//最外層的JSONObject對象
        JSONObject user = obj.getJSONObject("user");//通過user字段獲取其所包含的JSONObject對象
        String name = user.getString("name");//通過name字段獲取其所包含的字符串

        System.out.println(name);


    }
}

打印結果如下


alex

可以看到獲取到了相應的值。

JSONObject對象中封裝了getXXX()等一系列方法。用以獲取字符串,整形等等一系列的值。

對於如上例子,完全解析user對象如下

        String name = user.getString("name");//通過name字段獲取其所包含的字符串
        String age = user.getString("age");
        boolean isMan = user.getBoolean("isMan");

        System.out.println("name:"+name+"\nage:"+age+"\nisMan:"+isMan);

結果如下

name:alex
age:18
isMan:true

這種通過getXXX的方式,無疑會出現一些問題,我們開始一一嘗試。

getXXX方法獲取的類型不符
字符串類型轉整形

對於上面的例子,我們可以看到age字段雖然其對應的值是雙引號括起的字符串,但其實際上是一個整形,那麼我們是否能夠通過getInt獲取整形呢。

    int age = user.getInt("age");
    age:18

當然是可以得,同時字符串類型可以轉化為布爾類型,整數類型,浮點型等等。但字符串的內容必須符合規范,否則會報異常。如果看其源碼可知,其內部實質是調用了對應對象的parseXXX()方法進行轉化操作。

    //getInt源碼
  public int getInt(String key) throws JSONException {
        Object object = this.get(key);

        try {
            //關鍵點,如果是數值類型,則調用intValue(),否則強轉成字符串之後調用parserInt方法()
            return object instanceof Number?((Num,ber)object).intValue():Integer.parseInt((String)object);
        } catch (Exception var4) {
            throw new JSONException("JSONObject[" + quote(key) + "] is not an int.");
        }
    }
整形等轉字符串類型

按照如上的思維邏輯,直接getString("xxx")就可以了。但事實正好相反,該方法,如果對應值不是雙引號括起的,則會拋出異常。


 //getString 源碼
 public String getString(String key) throws JSONException {
        Object object = this.get(key);
        //直接判斷是否是字符串類型,如果不是,則拋出異常
        if(object instanceof String) {
            return (String)object;
        } else {
            throw new JSONException("JSONObject[" + quote(key) + "] not a string.");
        }
    }
getXXX(“”) 沒有對應的鍵值

通過上面的例子,可以得知getXXX("")方法是通過字段(鍵)獲取對應的值。那麼肯定存在一種情況,及沒有鍵的存在。

  System.out.println(user.getString("sex"));
Exception in thread "main" org.json.JSONException: JSONObject["sex"] not found.
    at org.json.JSONObject.get(JSONObject.java:471)
    at org.json.JSONObject.getString(JSONObject.java:717)
    at json.OrgJSONTest.main(OrgJSONTest.java:24)

果斷報異常。

那麼怎麼辦呢:使用optXXX()。後面會講。

JSONArray 解析

該對象用以解析[]的對象,及數組對象。用法類似,修改一下數據格式

{
    "user":[
        {
            "name":"alex",
            "age":"18",
            "isMan":true
        },
        {
            "name":"alex",
            "age":"18",
            "isMan":true
        }
    ]

}

user對應的值不再是一個JSONObject對象,而是一個JSONArray對象(數組對象)。該數組對象中包含了多個JSONObject

        JSONObject obj = new JSONObject(json);//最外層的JSONObject對象


        JSONArray array = obj.getJSONArray("user");

        for(int i = 0 ; i
alex
mahao

解析過程與JSONObject類似,多了一個遍歷JSONArray的步驟,把JSONArray當作JAVA中的數組對待使用。兩者使用方式幾乎一樣。

構造JSON 數據

對於POST請求,傳參數時一般都是傳入一個json數據。那麼如何構造json數據呢,使用字符串拼接可以,但很蛋疼。當然,JSONObject等提供了對應的方法。

使用如下:

        //外層obj對象
        JSONObject objWrite = new JSONObject();

        //user對象
        JSONObject userWrite = new JSONObject();

        //寫入對應屬性
        userWrite.put("name","alex");
        userWrite.put("age","18");
        userWrite.put("isMan",true);

        //將user對象寫入到外層obj中
        objWrite.put("user",userWrite);

        System.out.println(objWrite);
{"user":{"name":"alex","isMan":true,"age":"18"}}

opt 替代 get

在上面使用中,我們通過getXXX()獲取相應值。但是,會發現其局限性很多,很容易就拋異常,需要我們try...catch去捕獲。而optXXX()對此進行了優化。

首先看一下他的用法,在看用法之前,我們回憶之前使用get時的兩個問題

其他類型轉字符串類型拋出異常 當需要的字段沒有時,拋出異常。

看一下opt針對如上問題的解決:

 JSONObject obj = new JSONObject(json);//最外層的JSONObject對象


        JSONObject user = obj.optJSONObject("user");

        String name = user.optString("name");

        //整形轉字符串
        String age = user.optString("age");

        boolean isMan = user.optBoolean("isMan");

        //默認值,如果沒有該字段,則會返回默認值
        String sex = user.optString("sex","男");

        System.out.println("name:"+name+"\nage:"+age+"\nisMan:"+isMan+"\nsex:"+sex);
    name:alex
    age:18
    isMan:true
    sex:男

通過上面的例子,可以看出通過使用optString()可以將整形轉化為字符串。而對於sex,因為該字段沒有,會為其付默認值。解決了拋出異常的問題。

深入進去,看一下他們的源碼。

optString()

    // optString   默認調用了optString(key, ""); 
    public String optString(String key) {
        return this.optString(key, "");
    }

    //如果是null,返回默認值,否則調用toString方法返回
    public String optString(String key, String defaultValue) {
        Object object = this.opt(key);
        return NULL.equals(object)?defaultValue:object.toString();
    }

optBoolean
    public boolean optBoolean(String key) {
        return this.optBoolean(key, false);
    }

    //實質調用get方法,如果拋出異常,則賦默認值
    public boolean optBoolean(String key, boolean defaultValue) {
        try {
            return this.getBoolean(key);
        } catch (Exception var4) {
            return defaultValue;
        }
    }

get()取值不正確會拋出異常,必須用try catch或者throw包起

opt()取值不正確則會試圖進行轉化或者輸出友好值,不會拋出異常

如上,介紹了Android原生的解析,但在實際開發中,為了提高效率,往往使用第三方解析類庫,而下面我們將進入到第三方類庫的使用。

GSON 解析

Gson解析是google 提供的快速json解析庫。其和原生的相比,最大的優點是可以按照bean類對數據進行解析。

因為其屬於第三方庫,所以我們需要導包,如果使用的是AndroidStudio,直接搜索gson導入即可。

使用的是eclipse的話,則在該地址下載,將jar包加入到工程中。

Gson 解析單一實體類對象

還是上面的數據格式

{
    "user": {
        "name": "alex",
        "age": "18",
        "isMan": true
    }
}

對於該數據,我們想要獲取的是user中的字段值,首先定義User實體類,注意:該類名沒有要求,隨便命名。


public class User {

    private String name;

    private int age;

    private boolean isMan;

    private String sex;

}

有兩點需要注意:

類中成員變量名一定要和json數據中字段一一對應。 多添加了sex字段,測試當獲取的字段不存在時的情況。
 //使用Gson解析實體類對象

        //1, 獲取對應實體類對象的字符串,當前為user的值。

        String userJson = new JSONObject(json).getJSONObject("user").toString();

        //userJson = "{\"name\":\"alex\",\"age\":18,\"isMan\":true}";

        //2 , 創建Gson 對象

        Gson gson = new Gson();

        // 3, fromJson 解析
        User user = gson.fromJson(userJson, User.class);


        System.out.println(user);
User{name='alex', age=18, isMan=true, sex='null'}

關鍵方法為fromJson,該方法第一個參數為需要解析的json數據,第二個參數為需要解析成的目標對象的class。

因為該例子比較特殊,當前數據中user中的值不是最外層的json數據,他被包裹起來了,所以我們先把他剝開,獲取user對應的值。

有時候,返回的數據中字段值和我們前端的命名習慣不同,導致字段無法一一對應。如果我們的數據修改成了如下樣式

{
    "user": {
        "name": "alex",
        "age": "18",
        "is_man": true
    }
}

字段值得到了修改,isMan-》is_man,如果我們實體類也改成該字段名,那麼就不符合命名規范了。

在Gson中有如下注解@SerializedName

    @SerializedName("is_man")
    private boolean isMan;

這樣就解決了問題。

還有一種情況,如果對於該字段,有的地方使用is_man,有的地方使用is_Man,甚至還有isMan。那麼我們因為三個字段名的不同建立三個實體類,很是蛋疼。

  @SerializedName(value = "is_man",alternate = {"is_Man","isMan"})
    private boolean isMan;

當然,如果這三個字段同時出現時,會取最後一次出現的對應值進行賦值。

Gson 解析數組型實體類對象

對於例子,我們修改一下

{
    "user": [
        {
            "name": "alex",
            "age": "18",
            "is_man": true
        },
        {
            "name": "mahao",
            "age": "16",
            "is_man": true
        }
    ]
}

user中所對應的值不再是一個JSONObject,而是JSONArray類型。

 public static void parserArray(){
        String json = "{\"user\":[{\"name\":\"alex\",\"age\":18,\"isMan\":true},{\"name\":\"mahao\",\"age\":16,\"isMan\":true}]}";

        //1, 獲取對應實體類對象的字符串,當前為user的值。

        String userJson = new JSONObject(json).getJSONArray("user").toString();

        //2 ,創建Gson 對象

        Gson gson = new Gson();

        //3, 獲取user 數組
        User[] users = gson.fromJson(userJson, User[].class);

        System.out.println(users[1]);
    }

最終解析出了User[]數組。

平常我們往往使用List存儲數據。

第三步改成了如下代碼

 List users = gson.fromJson(userJson, List.class);

報錯!!! 因為第二個參數的字節碼,實際為List.class ,User被忽略了。 泛型擦除

Gson為我們提供了另一個方法解決該問題

List users = gson.fromJson(userJson,new TypeToken>(){}.getType());
        System.out.println(users.get(1));

通過Gson 構造json數據

根據實體類對象生成json 數據。
   public static void writeBeanJson(){

        //1 構造gson 對象
        Gson gson = new Gson();


        //2 構造對象

        User user = new User();

        user.setName("lala");

        user.setAge(20);

        // 3 生成json 數據

        String json = gson.toJson(user);

        System.out.println(json);
    }
    {"name":"lala","age":20,"is_man":false}

如果實體類中為null或空字符串,則該字段不會被轉化。當然也可以通過GsonBuilder設置,後面會提到。

自定義json數據。

對於POST請求,需要的json數據自定義比較大。例如登錄時,需要傳入賬號和密碼。

 private static void writeJson() {
        //1 構造gson 對象
        Gson gson = new Gson();

        //2 ,構建map對象
        Map map = new HashMap();
        map.put("username","haha");
        map.put("password",123456);

        //3 生成json數據
        String json = gson.toJson(map);

        System.out.println(json);

    }

Gson使用擴展

GsonBuilder ,通過該類初始化一些Gson的基本屬性

Gson gson = new GsonBuilder()
        //序列化null
        .serializeNulls()
        // 設置日期時間格式,另有2個重載方法
        // 在序列化和反序化時均生效
        .setDateFormat("yyyy-MM-dd")
        // 禁此序列化內部類
        .disableInnerClassSerialization()
        //生成不可執行的Json(多了 )]}' 這4個字符)
        .generateNonExecutableJson()
        //禁止轉義html標簽
        .disableHtmlEscaping()
        //格式化輸出
        .setPrettyPrinting()
        .create();

Gson的封裝

/**
 * gson 的基本封裝,完成Gson 解析中常用的功能
 * 備注人: Alex_MaHao
 * @date 創建時間:2016年6月6日 下午4:33:25
 */
public class GsonUtil {

    private static Gson gson = null;

    static {
        if (gson == null) {
            gson = new Gson();
        }
    }

    private GsonUtil() {

    }

    /**
     * 
     * 對象轉化為json 數據
     * @param object 需要轉化的對象
     * @return
     */
    public static String GsonString(Object object) {
        String gsonString = null;
        if (gson != null) {
            gsonString = gson.toJson(object);
        }
        return gsonString;
    }

    /**
     * json 數據轉化為實體類對象
     * 
     * @param gsonString
     * @param cls
     * @return
     */
    public static  T GsonToBean(String gsonString, Class cls) {
        T t = null;
        if (gson != null) {
            t = gson.fromJson(gsonString, cls);
        }
        return t;
    }

    /**
     * 
     * Json 數據轉化為List集合--集合中為實體類
     * 
     * @param gsonString
     * @param cls
     * @return
     */
    public static  List GsonToList(String gsonString, Class cls) {
        ArrayList mList = new ArrayList();
        JsonArray array = new JsonParser().parse(gsonString).getAsJsonArray();
        for (final JsonElement elem : array) {
            mList.add(gson.fromJson(elem, cls));
        }
        return mList;

    }

    /**
     * 將數據轉化成List集合--集合中為map
     * 
     * @param gsonString
     * @return
     */
    public static  List> GsonToListMaps(String gsonString) {
        List> list = null;
        if (gson != null) {
            list = gson.fromJson(gsonString,
                    new TypeToken>>() {
                    }.getType());
        }
        return list;
    }

    /**
     * 將json數據轉化成map
     * 
     * @param gsonString
     * @return
     */
    public static  Map GsonToMaps(String gsonString) {
        Map map = null;
        if (gson != null) {
            map = gson.fromJson(gsonString, new TypeToken>() {
            }.getType());
        }
        return map;
    }
}

fastJson

fastJson 是阿裡巴巴出的第三方庫。該庫的使用非常的方便而且強大。但是用的並不多,大家都是用Gson。雖然不知道原因是為什麼。

使用fastJson有一個很大的缺陷,就是其命名與Android 原生的解析命名相同,所以在使用中很容易混淆。

解析對象

   public static void  parserObject(){

        String json = "{\"user\":{\"name\":\"alex\",\"age\":18,\"isMan\":true}}";

        //1, 獲取對應實體類對象的字符串,當前為user的值。 該JSONObject 為org包中的。。
        String userJson = new JSONObject(json).getJSONObject("user").toString();

        //2 調用JSON.parserObject 解析
        User user = JSON.parseObject(userJson, User.class);

        System.out.print(user);
    }
User{name='alex', age=18, isMan=true, sex='null'}

解析數組

 public static void parserArray(){
        String json = "{\"user\":[{\"name\":\"alex\",\"age\":18,\"isMan\":true},{\"name\":\"mahao\",\"age\":16,\"isMan\":true}]}";

        //1, 獲取對應實體類對象的字符串,當前為user的值。

        String userJson = new JSONObject(json).getJSONArray("user").toString();

        //2 調用JSON.parseArray 解析
        List users = JSON.parseArray(userJson, User.class);

        System.out.println(users.get(1));

    }
User{name='mahao', age=16, isMan=true, sex='null'}

構造json 數據

 public static void wirteJson(){

        Map map = new HashMap();
        map.put("username","haha");
        map.put("password",123456);

        String json = JSON.toJSONString(map);

        System.out.println(json);
    }
{"password":123456,"username":"haha"}

通過上面的例子看出,使用fastJson 更加的簡單,方便。主要通過JSON.parseArray,JSON.paseObject,JSON.toJSONString進行數據的解析和生成。

GsonFormat

在上面的例子中,使用GsonfastJson解析數據時,關鍵的便是實體類。 但有時候實體類非常復雜時,我們比著敲時很容易出錯。

在這裡使用GsonFormat插件,該插件為Android Studio的插件。

File -》 setting -》plugins -> 搜索GsonFormat,導入即可。

使用方式如下圖:

點擊Alt+insert

這裡寫圖片描述

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved