關(guān)于NotSerializableException: com.google.gson.internal.StringMap問題總結(jié)

最近項(xiàng)目進(jìn)行了一次target sdk的升級28版本的改造,在處理了一些target 版本的Android9.0的兼容之后,項(xiàng)目整體運(yùn)行起來沒有什么問題,但在之后作為SDK給另一個(gè)項(xiàng)目使用之后出現(xiàn)了一個(gè)比較罕見的問題-NotSerializableException: com.google.gson.internal.StringMap數(shù)據(jù)序列化問題,看似比較簡單,也是困擾了很久,下面總結(jié)一下針對這個(gè)問題的跟蹤查詢。


錯(cuò)誤日志

一、問題描述

? ? 我在進(jìn)行功能驗(yàn)證的過程中發(fā)現(xiàn)了一個(gè)比較奇怪的問題,當(dāng)我在頁面A的時(shí)候數(shù)據(jù)沒有任何問題,也可以正常顯示,但是不管我從頁面A(Fragment)跳轉(zhuǎn)到任何頁面B、C、D(Activity,F(xiàn)ragment都行)都會(huì)崩潰,控制臺輸出問題截圖上面的的異常信息。然而我從其他頁面E(Fragment)跳轉(zhuǎn)到B、C、D的時(shí)候都沒有任何問題。

????根據(jù)控制臺的異常日志輸出信息可以看出這就是一個(gè)簡單的序列化問題,剛開始我是這么認(rèn)為的,日志信息明確說明了是PageBean的寫入數(shù)列化問題,那我們就找PageBean然后實(shí)現(xiàn)序列化就可以了。當(dāng)我找到PageBean的時(shí)候就懵了?public class PageBeanimplements Serializable {},明明都已經(jīng)實(shí)現(xiàn)了Serializable 接口了,為什么還是報(bào)錯(cuò)了,是不是子類沒有實(shí)現(xiàn)Serializable 接口呢!然后我仔細(xì)檢查了PageBean的每個(gè)子類以及子類的子類,全部都實(shí)現(xiàn)了Serializable 接口,問題開始變得復(fù)雜了。回頭又看錯(cuò)誤日志,發(fā)現(xiàn)還有一個(gè)信息,就是StringMap這個(gè)類,但是我搜索了一個(gè)引用的gson庫并沒有找個(gè)這個(gè)文件。

二、問題定位?

我把問題同步給了項(xiàng)目leader,經(jīng)過leader跟同事的連夜查找,總算是大概定位到了問題所在,而且也找到了StringMap這個(gè)類。那天我早早的可恥的溜了,事后也是感到非常的慚愧。原來StringMap是在早些的gson庫里所存在幫助json數(shù)據(jù)解析的類,而我們的項(xiàng)目的gson比較新,所以一直找不到這個(gè)類,我們的另一個(gè)項(xiàng)目是早些的gson庫,所以打包后到另一個(gè)項(xiàng)目才會(huì)出現(xiàn)此問題。出問題的地方大概在下面所存在的寫入序列化對象的代碼中

public static TemplateContainerFragment newInstance(ChannelNavBean channelNavBean, PageBean firstPageBean) {

????TemplateContainerFragment vesselFragment = new TemplateContainerFragment();

????Bundle bundle = new Bundle();

????bundle.putSerializable(AppParams.INTENT_PARAM_CHANNEL_NAV_BEAN, channelNavBean);

? ? if (firstPageBean != null) {

? ? ????bundle.putSerializable(AppParams.INTENT_PARAM_CHANNEL_PAGE_BEAN, firstPageBean);

????}

????vesselFragment.setArguments(bundle);

????return vesselFragment;

}

大概定到問題以后,leader為了鍛煉我解決問題的能力,也是拋給我2個(gè)問題,希望我能多提高自己解決問題的能力

????1.序列化是在什么時(shí)候出問題的?出問題的序列化對象在什么位置上?SrtingMap對象在當(dāng)中扮演的角色是什么?

????2.為什么頁面初始化的時(shí)候沒有問題,反而在進(jìn)入下一級頁面的時(shí)候出現(xiàn)崩潰?

三、問題分析

? ? 根據(jù)日志信息和已找到的代碼可以大概確定PageBean是在序列化的時(shí)候出現(xiàn)了問題,我找到上面的相關(guān)代碼進(jìn)行debug驗(yàn)證,尋找PageBean中未實(shí)現(xiàn)序列化的StringMap對象,還真的有所發(fā)現(xiàn)

產(chǎn)生StringMap的PageBean

? ? 為什么PageBean里面會(huì)有StringMap對象?帶著這個(gè)疑問我跟蹤查找了一個(gè)StringMap的產(chǎn)生,終于在gson庫里面的ObjectTypeAdapter對象中找到了StringMap的產(chǎn)生,原來是在數(shù)據(jù)解析的時(shí)候如果有JSONArray有未知的List<Object> list,Object會(huì)被轉(zhuǎn)化成為一個(gè)StringMap對象存儲,而StringMap是沒有序列化的對象,所以在傳遞數(shù)據(jù)的過程中會(huì)出現(xiàn)異常。那么第一個(gè)問題就找到了答案

public Object read(JsonReader in) throws IOException {

????JsonToken token = in.peek();

????switch(token) {

????????case BEGIN_ARRAY:

????????????????List<Object> list = new ArrayList();

????????????????in.beginArray();

????????while(in.hasNext()) {

????????????list.add(this.read(in));

????????}

????????in.endArray();

????????return list;

????????case BEGIN_OBJECT:

????????????????Map<String, Object> map = new StringMap();

????????????????in.beginObject();

????????while(in.hasNext()) {

????????????map.put(in.nextName(), this.read(in));

????????}

????????in.endObject();

????????return map;

????????case STRING:

????????????????return in.nextString();

????????case NUMBER:

????????????????return in.nextDouble();

????????case BOOLEAN:

????????????????return in.nextBoolean();

????????case NULL:

????????????????in.nextNull();

????????????????return null;

????????default:

????????????????throw new IllegalStateException();

????}

}

? ? 剩下的問題就是這個(gè)方法明明是在頁面初始化的時(shí)候調(diào)用的,為什么在頁面初始化的時(shí)候沒有問題,返回再頁面進(jìn)入下一級頁面的時(shí)候回出現(xiàn)崩潰?其實(shí)發(fā)現(xiàn)進(jìn)入下一個(gè)頁面的時(shí)候出現(xiàn)問題,也就發(fā)現(xiàn)了思路,進(jìn)入下一級頁面的時(shí)候上一個(gè)頁面要保存數(shù)據(jù),對,就是保存數(shù)據(jù)的時(shí)候可能會(huì)出現(xiàn)問題,然后我就跟蹤onSaveInstanceState(@NonNull Bundle outState)的方法,頁面離開確實(shí)調(diào)用了該方法,但是outState參數(shù)是空的,沒有傳遞任何數(shù)據(jù),為什么會(huì)出問題呢,經(jīng)過一系列的跟蹤,終于在FragmentState中發(fā)現(xiàn)了問題,原來在fragment頁面

@Override

public void writeToParcel(Parcel dest, int flags) {

????dest.writeString(mClassName);

????dest.writeInt(mIndex);

????dest.writeInt(mFromLayout ? 1 : 0);

????dest.writeInt(mFragmentId);

????dest.writeInt(mContainerId);

????dest.writeString(mTag);

????dest.writeInt(mRetainInstance ? 1 : 0);

????dest.writeInt(mDetached ? 1 : 0);

????dest.writeBundle(mArguments);

????dest.writeInt(mHidden ? 1 : 0);

????dest.writeBundle(mSavedFragmentState);

}

Parcel類的writeBundle
bundle類的writeToParcel
writeToParcelInner
writeArrayMapInternal

? ? ? ? for循環(huán)寫入數(shù)據(jù)

writeValue

? ? 寫入數(shù)據(jù),原來這里要求寫入的數(shù)據(jù)對象以及子對象都必須是序列化的數(shù)據(jù),否則就會(huì)出現(xiàn)異常。為什么頁面初始化進(jìn)入寫入的數(shù)據(jù)沒有問題,反而在頁面離開保存數(shù)據(jù)的時(shí)候?qū)懭氲臄?shù)據(jù)會(huì)出現(xiàn)異常?帶著這個(gè)疑問我又看了一下bundle.putSerializable()這個(gè)方法。

Bundle的putSerializable方法
putSerializable

? ? 看到代碼之后我釋然了,原來putSerializable這個(gè)方法值值要求傳入的對象被序列化就可以,并不要求子對象必須都實(shí)現(xiàn)數(shù)列化接口。所以才導(dǎo)致頁面初始化的時(shí)候并沒有問題,反而在頁面離開保存數(shù)據(jù)的時(shí)候?qū)懭霐?shù)據(jù)異常。

四、問題跟蹤解決

由于我們的數(shù)據(jù)PageBean的解析里面JSONArray出現(xiàn)的問題,所以就嘗試在不改變gson庫版本號的同時(shí)解決這個(gè)問題,于是根據(jù)返回的數(shù)據(jù)結(jié)構(gòu)嘗試把JSONAarray替換成List<JSONObject>形式,于是又做了一番兼容的嘗試工作,但是由于我們的數(shù)據(jù)結(jié)構(gòu)問題,并沒有成功,最后還是報(bào)出了相同的錯(cuò)誤,經(jīng)過查看還JSONObject中還是出現(xiàn)了沒有序列化的StringMap。

仍然有問題的PageBean

最后只能溝通把另一個(gè)項(xiàng)目的gson庫進(jìn)行升級解決這個(gè)問題。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 泛型: https://juejin.im/post/5b614848e51d45355d51f792#headi...
    RexHuang閱讀 7,067評論 0 0
  • 概況 Gson是一個(gè)Java庫,它可以用來把Java對象轉(zhuǎn)換為JSON表達(dá)式,也可以反過來把JSON字符串轉(zhuǎn)換成與...
    木豚閱讀 6,999評論 0 2
  • 1.概述2.Gson的目標(biāo)3.Gson的性能和擴(kuò)展性4.Gson的使用者5.如何使用Gson 通過Maven來使用...
    人失格閱讀 14,557評論 2 18
  • ORA-00001: 違反唯一約束條件 (.) 錯(cuò)誤說明:當(dāng)在唯一索引所對應(yīng)的列上鍵入重復(fù)值時(shí),會(huì)觸發(fā)此異常。 O...
    我想起個(gè)好名字閱讀 5,967評論 0 9
  • 為了更好的學(xué)習(xí)Gson,特將Gson User Guide翻譯如下。由于本人英文水平有限,如有錯(cuò)誤,還請指正,謝謝...
    WeberLisper閱讀 7,055評論 0 6

友情鏈接更多精彩內(nèi)容