1. 程式人生 > >Kotlin入門(31)JSON字串的解析

Kotlin入門(31)JSON字串的解析

json是App進行網路通訊最常見的資料互動格式,Android也自帶了json格式的處理工具包org.json,該工具包主要提供了JSONObject(json物件)與JSONArray(json陣列)的解析處理。下面分別介紹這兩個工具類的用法:
1、JSONObject
JSONObject的常用方法如下所示:
建構函式 : 從指定字串構造出一個JSONObject物件。
getJSONObject : 獲取指定名稱的JSONObject物件。
getString : 獲取指定名稱的字串。
getInt : 獲取指定名稱的整型數。
getDouble : 獲取指定名稱的雙精度數。
getBoolean : 獲取指定名稱的布林數。
getJSONArray : 獲取指定名稱的JSONArray陣列物件。
put : 新增一個JSONObject物件。
toString : 把當前JSONObject輸出為一個json字串。
2、JSONArray


JSONArray的常用方法如下所示:
length : 獲取JSONArray陣列物件的長度。
getJSONObject : 獲取JSONArray陣列物件在指定位置處的JSONObject物件。
put : 往JSONArray陣列物件中新增一個JSONObject物件。
使用JSONObject和JSONArray對json串進行手工解析,處理過程比較常規,完成該功能的Kotlin程式碼與Java程式碼大同小異。下面直接給出Kotlin解析json串的常用程式碼片段,包括如何構造json串、如何解析json串,以及如何遍歷json串:

    //構造json串
    private val jsonStr: String
        get() {
            val obj = JSONObject()
            obj.put("name", "地址資訊")
            val array = JSONArray()
            for (i in 0..2) {
                val item = JSONObject()
                item.put("item", "第${i+1}個元素")
                array.put(item)
            }
            obj.put("list", array)
            obj.put("count", array.length())
            obj.put("desc", "這是測試串")
            return obj.toString()
        }

    //解析json串
    private fun parserJson(jsonStr: String?): String {
        val obj = JSONObject(jsonStr)
        var result = "name=${obj.getString("name")}\n" +
                "desc=${obj.getString("desc")}\n" +
                "count=${obj.getInt("count")}\n"
        val listArray = obj.getJSONArray("list")
        //util表示的範圍是左閉右開區間。以下語句相當於for (i in 0..listArray.length() - 1)
        for (i in 0 until listArray.length()) {
            val item = listArray.getJSONObject(i)
            result = "${result}\titem=${item.getString("item")}\n"
        }
        return result
    }

    //遍歷json串
    private fun traverseJson(jsonStr: String?): String {
        var result = ""
        val obj = JSONObject(jsonStr)
        val it = obj.keys()
        while (it.hasNext()) { // 遍歷JSONObject
            var key = it.next().toString()
            result = "${result}key=$key, value=${obj.getString(key)}\n"
        }
        return result
    }

前面提到Kotlin對json串的手工解析沒有什麼好辦法,其實是有更高層次的辦法。手工解析json串實在是麻煩,費時費力還容易犯錯,所以好漢不吃眼前虧,此路難走不如另尋捷徑,捷徑便是甩開手工解析幾條街的自動解析。

既然是自動解析,首先要制定一個規則,約定json串有哪些元素,具體對應怎樣的資料結構;其次還得有個自動解析的工具,俗話說得好,沒有金剛鑽、不攬瓷器活。對於捷徑第一要素的json資料結構定義,Kotlin特有的資料類正好派上用場了,欄位名、欄位型別、欄位預設值等色香味俱全,還有equals、copy、toString等下酒小菜,只要開發者輕拉珠簾便是一大桌的滿漢全席。到底有多麼省事,且看下面的使用者資訊資料類,包括姓名、年齡、身高體重、婚否等欄位存取在內的完整功能,僅需一行Kotlin程式碼就全部搞定了:

data class UserInfo(var name: String="", var age: Int=0, var height: Long=0L, var weight: Float=0F, var married: Boolean=false)

 

接著解決捷徑第二要素的工具使用,json解析除了系統自帶的org.json,谷歌公司也提供了一個增強庫gson,專門用於json串的自動解析。不過由於是第三方庫,因此首先要修改模組的build.gradle檔案,在裡面的dependencies節點下新增下面一行配置,表示匯入指定版本的gson庫:

    compile "com.google.code.gson:gson:2.8.2"

 

其次還要在kt原始碼檔案頭部新增如下一行匯入語句,表示後面會用到Gson工具類:

import com.google.gson.Gson

 

完成了以上兩個步驟,然後就能在程式碼中呼叫Gson的各種處理方法了,Gson常用的方法有兩個,一個名叫toJson,可把資料物件轉換為json字串;另一個名叫fromJson,可將json字串自動解析為資料物件,方法呼叫的程式碼格式為“fromJson(json串, 資料類的類名::class.java)”。Kotlin的資料類定義程式碼尚且只有一行,這裡的json串自動解析仍舊只需一行程式碼,實實在在為開發者節省了不少功夫。下面是個通過gson庫實現json自動解析的Kotlin程式碼例子:

class JsonConvertActivity : AppCompatActivity() {
    private val user = UserInfo(name="阿四", age=25, height=160L, weight=45.0f, married=false)
    private val json = Gson().toJson(user)

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_json_convert)
        btn_origin_json.setOnClickListener { tv_json.text = "json串內容如下:\n$json" }
        btn_convert_json.setOnClickListener {
            //利用Gson包直接將json串解析為對應格式的資料類物件
            val newUser = Gson().fromJson(json, UserInfo::class.java)
            tv_json.text = "從json串解析而來的使用者資訊如下:" +
                    "\n\t姓名=${newUser.name}" +
                    "\n\t年齡=${newUser.age}" +
                    "\n\t身高=${newUser.height}" +
                    "\n\t體重=${newUser.weight}" +
                    "\n\t婚否=${newUser.married}"
        }
    }
}