使用Gson解析泛型型別
在程式中訪問網路的時候返回的Json有時候是固定的形式,我們所需要的json資訊是以巢狀的形式給出的,比如
User info:
{
"result_code":"4000",
"result_msg":"接受資料正常",
"json_msg":{
"user_name":"jack",
"user_age":15
}
}
Book info:
{
"result_code":"4000",
"result_msg":"接受資料正常",
"json_msg":{
"book_name":"Java程式設計思想" ,
"book_price":"108.00"
}
}
如果我們直接用Gson解析的話,要有對應的實體類才行,比如要解析上面的兩個Json的話,就要有兩個類
public class UsreInfoBean {
public String result_code;
public String result_msg;
public UserInfo json_msg;
}
public class BookInfoBean {
public String result_code;
public String result_msg;
public BookInfo json_msg;
}
另外還需要UserInfo和BookInfo兩個類:
public class UserInfo {
public String user_name;
public int user_age;
}
public class BookInfo{
public String book_name;
public String book_price;
}
這樣的話每個Json都要對應兩個類,很繁瑣,另外如果Json比較多的話,會產生很多類,而這些類有一半都是多餘的,維護起來也很麻煩。
觀察UserInfoBean和BookInfoBean兩個類,可以發現這兩個類中的成員變數除了json_msg欄位的型別不一樣,其他的都完全一樣,如果能把這連個類統一成一個類的話就能解決類多餘的問題。Java的泛型恰好可以解決這個問題。上面的連個類用泛型可以寫為:
public class InfoBean<T> {
public String result_code;
public String result_msg;
public T json_msg;
}
此時,UserInfoBean和BookInfoBean兩個類就可以寫成InfoBean和InfoBean,不管有多上類都可以寫成這種形式。
試著我們常用的Gson用法去去解析json,
String json = ...; //對應上面的User info的json
//下面程式碼在android studio中會報錯
InfoBean<UserInfo> userInfo = new Gson().fromJson(json, InfoBean<UserInfo>.class);
上面的程式碼並不能執行,原因是InfoBean是泛型,並不能直接獲取class型別。通過android studio的程式碼提示功能可以看到Gson的fromJson()方法解析String型別的json有兩種:
Object fromJson(Sting, Class<Object>)
Object fromJson(String, Type)
第一個方法就是我們一般常用的,接受class型別, 第二個方法接受一個Type型別,Type型別一般與與泛型的型別推斷有關,查閱這個方法的文件可以發現這個方法就是用來處理泛型型別的,文件中介紹需要用TypeToken來獲取泛型的type型別,並且給出了具體的用法:
Type typeOfT = new TypeToken<Collection<Foo>>(){}.getType();
按照上面的形式現在我們來處理InfoBean:
String json = ...; //對應上面的User info的json
Type type = new TypeToken<InfoBean<UserInfo>>(){}.getType();
InfoBean<UserInfo> userInfo = new Gson.fromJson(json, type);
現在就可以正確的獲取userInfo物件了。
另外,一般情況下,在json對應的實體類中,類的成員變數的名字要和json對應欄位的名字一樣才能正確解析,比如上面的User info的json中的”result_code”欄位在InfoBean類中要有result_code成員變數來對應。而我們在開發安卓程式的時候一般習慣用駝峰命名法,即result_code欄位一般習慣用resultCode來命名。
Gson對這種情況也是有處理的,只要使用一個註解就可以解決問題:
@SerializedName("result_code")
註解中的名字對應json中的欄位名字,這時我們就可以對實體類中的成員變數隨便命名了。對InfoBean加上註解後:
public class InfoBean<T> {
@SerializedName("result_code")
public String resultCode;
@SerializedName("result_msg")
public String resultMsg;
@SerializedName("json_msg")
public T resultObj;
}
這樣我們在程式碼中訪問json實體類的時候,程式碼的閱讀性就會提高很多。