引言
Gson是不是很簡潔很容易上手呢?最主要的就兩個方法toJson()和fromJson()將實體轉爲Json和將Json轉爲實體。
我之前沒有使用過Gson,更不用說是用Kotlin了。由於使用的時間還不是很長,好不好用還真不好說。
我之前用慣了Json且有這個JsonHelper工具類的幫助,暫時性的認爲沒有JsonHelper好用且功能不如JsonHelper的實用。
主要是因爲碰到了下文將要講述的坑。
正文
我在編寫項目的過程中,需要將一些暫時性的數據進行保存,自然而然的就想到了之前創建的SpUtils類將數據存儲在SharedPreferences中。
於是寫了兩個方法,完美實現需求
fun <T> getObject(key: String, cls: Class<T>): T {
var value = getString(key, "")
return gson.fromJson<T>(value, cls)
}
fun setObject(key: String, obj: Any) {
var value = gson.toJson(obj)
setString(key, value)
}
思路主要是將實體轉換成Json字符串保存,需要時取出Json字符串並序列化成實體返回。
這時需求升級了,需要保存一個列表。
fun <T> getList(key: String, cls: Class<T>): List<T> {
var value = getString(key, "")
if (TextUtils.isEmpty(value)) {
return ArrayList()
}
return gson.fromJson(value, object : TypeToken<List<T>>() {}.type)
}
這時看着沒毛病吧,程序也能夠正常的編譯,但運行到取實體的變量時卻崩潰了
類型轉換失敗??爲什麼呢??debug走一遍
問題出現了,原本List裏面包含的對象,經過一遍存儲和取出,List裏卻變成了鍵值對。
可以得出結論Gson並沒有序列化成功。
費了不少心思,搜尋了很多資料,終於明白了。原因是java的類型擦除
Java中的泛型基本上都是在編譯器這個層次來實現的。在生成的Java字節碼中是不包含泛型中的類型信息的。使用泛型的時候加上的類型參數,會在編譯器在編譯的時候去掉。這個過程就稱爲類型擦除。
https://segmentfault.com/q/1010000009644038
由於我是用了泛型,導致fromJson()只知道是List而裏面的類型卻是未知的,因此返回成了鍵值對。
所以這裏採用傳遞type的方式,否則會因爲找不到類型,而序列化失敗
fun <T> getList(key: String, type: Type): T {
var value = getString(key, "")
return gson.fromJson(value, type)
}
SpUtils.getList<List<Category>>(KEY_CATEGORY_LIST, object : TypeToken<List<Category>>() {}.type)
從這一點看之前的JsonHelper就不會有這種問題。
不能一棍子打死,我還是抱着學習的態度繼續深入。