主頁 > 移動端開發 > Android序列化問題與思考

Android序列化問題與思考

2020-11-12 11:30:37 移動端開發

今天再來談談Android中的物件序列化,你了解多少呢?

序列化指的是什么?有什么用

序列化指的是講物件變成有序的位元組流,變成位元組流之后才能進行傳輸存盤等一系列操作,
反序列化就是序列化的相反操作,也就是把序列化生成的位元組流轉為我們記憶體的物件,

介紹下Android中兩種序列化介面

Serializable

Java提供的一個序列化介面,是一個空介面,專門為物件提供序列化和反序列化操作,具體使用如下:

public class User implements Serializable {
    private static final long serialVersionUID=519067123721561165l;
    
    private int id;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }
}

實作Serializable介面,宣告一個serialVersionUID

到這里可能有人就問了,不對啊,平時沒有這個serialVersionUID啊,沒錯,serialVersionUID不是必須的,因為不寫的話,系統會自動生成這個變數,它有什么用呢?當序列化的時候,系統會把當前類的serialVersionUID寫入序列化的檔案中,當反序列化的時候會去檢測這個serialVersionUID,看他是否和當前類的serialVersionUID一致,一樣則可以正常反序列化,如果不一樣就會報錯了,

所以這個serialVersionUID就是序列化和反序列化程序中的一個標識,代表一致性,不加的話會有什么影響?如果我們序列化后,改動了這個類的某些成員變數,那么serialVersionUID就會改變,這時候再拿之前序列化的資料來反序列化就會報錯,所以如果我們手動指定serialVersionUID就能保證最大限度來恢復資料,

Serializable的實質其實是是把Java物件序列化為二進制檔案,然后就能在行程之間傳遞,并且用于網路傳輸或者本地存盤等一系列操作,因為他的本質就存盤了檔案,可以看看原始碼:


private void writeObject0(Object obj, boolean unshared)
    throws IOException
{
    ...
    try {
     
        Object orig = obj;
        Class<?> cl = obj.getClass();
        ObjectStreamClass desc;
       
        desc = ObjectStreamClass.lookup(cl, true);
   
        if (obj instanceof Class) {
            writeClass((Class) obj, unshared);
        } else if (obj instanceof ObjectStreamClass) {
            writeClassDesc((ObjectStreamClass) obj, unshared);
        // END Android-changed:  Make Class and ObjectStreamClass replaceable.
        } else if (obj instanceof String) {
            writeString((String) obj, unshared);
        } else if (cl.isArray()) {
            writeArray(obj, desc, unshared);
        } else if (obj instanceof Enum) {
            writeEnum((Enum<?>) obj, desc, unshared);
        } else if (obj instanceof Serializable) {
            writeOrdinaryObject(obj, desc, unshared);
        } else {
            if (extendedDebugInfo) {
                throw new NotSerializableException(
                    cl.getName() + "\n" + debugInfoStack.toString());
            } else {
                throw new NotSerializableException(cl.getName());
            }
        }
    } 
    ...
}


private void writeOrdinaryObject(Object obj,
                                     ObjectStreamClass desc,
                                     boolean unshared)
        throws IOException
    {
        ...
        try {
            desc.checkSerialize();
            
            //寫入二進制檔案,普通物件開頭的魔數0x73
            bout.writeByte(TC_OBJECT);
            //寫入對應的類的描述符,見底下原始碼
            writeClassDesc(desc, false);
            
            handles.assign(unshared ? null : obj);
            if (desc.isExternalizable() && !desc.isProxy()) {
                writeExternalData((Externalizable) obj);
            } else {
                writeSerialData(obj, desc);
            }
        } finally {
            if (extendedDebugInfo) {
                debugInfoStack.pop();
            }
        }
    }

    public long getSerialVersionUID() {
        // 如果沒有定義serialVersionUID,序列化機制就會呼叫一個函式根據類內部的屬性等計算出一個hash值
        if (suid == null) {
            suid = AccessController.doPrivileged(
                new PrivilegedAction<Long>() {
                    public Long run() {
                        return computeDefaultSUID(cl);
                    }
                }
            );
        }
        return suid.longValue();
    }

可以看到是通過反射獲取物件以及物件屬性的相關資訊,然后將資料寫到了一個二進制檔案,并且寫入了序列化協議版本等等,
而獲取·serialVersionUID·的邏輯也體現出來,如果id為空則會生成計算一個hash值,

Parcelable

Android自帶的介面,使用起來要麻煩很多:需要實作Parcelable介面,重寫describeContents(),writeToParcel(Parcel dest, @WriteFlags int flags),并添加一個靜態成員變數CREATOR并實作Parcelable.Creator介面

public class User implements Parcelable {
    
    private int id;

    protected User(Parcel in) {
        id = in.readInt();
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(id);
    }

    @Override
    public int describeContents() {
        return 0;
    }

    public static final Creator<User> CREATOR = new Creator<User>() {
        @Override
        public User createFromParcel(Parcel in) {
            return new User(in);
        }

        @Override
        public User[] newArray(int size) {
            return new User[size];
        }
    };

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }
}

  • createFromParcel,User(Parcel in) ,代表從序列化的物件中創建原始物件
  • newArray,代表創建指定長度的原始物件陣列
  • writeToParcel,代表將當前物件寫入到序列化結構中,
  • describeContents,代表回傳當前物件的內容描述,如果還有檔案描述符,回傳1,否則回傳0,

Parcelable的存盤是通過Parcel存盤到記憶體的,簡單地說,Parcel提供了一套機制,可以將序列化之后的資料寫入到一個共享記憶體中,其他行程通過Parcel可以從這塊共享記憶體中讀出位元組流,并反序列化成物件,

這其中實際又是通過native方法實作的,具體邏輯我就沒有去分析了,如果有大神朋友可以在評論區決議下,

當然,Parcelable也是可以持久化的,涉及到Parcel中的unmarshallmarshall方法, 這里簡單貼一下代碼:

protected void saveParce() {
        FileOutputStream fos;
        try {
            fos = getApplicationContext().openFileOutput(TAG,
                    Context.MODE_PRIVATE);
            BufferedOutputStream bos = new BufferedOutputStream(fos);
            Parcel parcel = Parcel.obtain();
            parcel.writeParcelable(new ParceData(), 0);

            bos.write(parcel.marshall());
            bos.flush();
            bos.close();
            fos.flush();
            fos.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    protected void loadParce() {
        FileInputStream fis;
        try {
            fis = getApplicationContext().openFileInput(TAG);
            byte[] bytes = new byte[fis.available()];
            fis.read(bytes);
            Parcel parcel = Parcel.obtain();
            parcel.unmarshall(bytes, 0, bytes.length);
            parcel.setDataPosition(0);

            ParceData data = https://www.cnblogs.com/jimuzz/archive/2020/11/12/parcel.readParcelable(ParceData.class.getClassLoader());
            fis.close();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

總結

0)兩者的區別,我們該怎么選擇?

Serializable是Java提供的序列化介面,使用簡單但是開銷很大,序列化和反序列化程序都需要大量I/O操作,
Parcelable是Android中提供的,也是Android中推薦的序列化方式,雖然使用麻煩,但是效率很高,

所以,如果是記憶體序列化層面,那么還是建議Parcelable,因為他效率會比較高,
如果是網路傳輸和存盤磁盤情況,就推薦Serializable,因為序列化方式比較簡單,而且Parcelable不能保證,當外部條件發生變化時資料的連續性,

1)對于記憶體序列化方面建議用Parcelable,為什么呢?

  • 因為Serializable是存盤了一個二進制檔案,所以會有頻繁的IO操作,消耗也比較大,而且用到了大量反射,反射操作也是耗時的,相比之下Parcelable就要效率高很多,

2)對于資料持久化還是建議用Serializable,為什么呢?

  • 首先,Serializable本身就是存盤到二進制檔案,所以用于持久化比較方便,而Parcelable序列化是在記憶體中操作,如果行程關倍訓者重啟的時候,記憶體中的資料就會消失,那么Parcelable序列化用來持久化就有可能會失敗,也就是資料不會連續完整,而且Parcelable還有一個問題是兼容性,每個Android版本可能內部實作都不一樣,知識用于記憶體中也就是傳遞資料的話是不影響的,但是如果持久化可能就會有問題了,低版本的資料拿到高版本可能會出現兼容性問題, 所以還是建議用Serializable進行持久化,

3)Parcelable一定比Serializable快嗎?

  • 有個比較有趣的例子是:當序列化一個超級大的物件圖表(表示通過一個物件,擁有通過某路徑能訪問到其他很多的物件),并且每個物件有10個以上屬性時,并且Serializable實作了writeObject()以及readObject(),在平均每臺安卓設備上,Serializable序列化速度大于Parcelable 3.6倍,反序列化速度大于1.6倍.

具體原因就是因為Serilazable的實作方式中,是有快取的概念的,當一個物件被決議過后,將會快取在HandleTable中,當下一次決議到同一種型別的物件后,便可以向二進制流中,寫入對應的快取索引即可,但是對于Parcel來說,沒有這種概念,每一次的序列化都是獨立的,每一個物件,都當作一種新的物件以及新的型別的方式來處理,

參考

Parcelable

拜拜

有一起學習的小伙伴可以關注下??我的公眾號——碼上積木,每天剖析一個知識點,我們一起積累知識,

轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/211801.html

標籤:其他

上一篇:Android序列化問題與思考

下一篇:Android adb 環境搭建遇到的問題

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【從零開始擼一個App】Dagger2

    Dagger2是一個IOC框架,一般用于Android平臺,第一次接觸的朋友,一定會被搞得暈頭轉向。它延續了Java平臺Spring框架代碼碎片化,注解滿天飛的傳統。嘗試將各處代碼片段串聯起來,理清思緒,真不是件容易的事。更不用說還有各版本細微的差別。 與Spring不同的是,Spring是通過反射 ......

    uj5u.com 2020-09-10 06:57:59 more
  • Flutter Weekly Issue 66

    新聞 Flutter 季度調研結果分享 教程 Flutter+FaaS一體化任務編排的思考與設計 詳解Dart中如何通過注解生成代碼 GitHub 用對了嗎?Flutter 團隊分享如何管理大型開源專案 插件 flutter-bubble-tab-indicator A Flutter librar ......

    uj5u.com 2020-09-10 06:58:52 more
  • Proguard 常用規則

    介紹 Proguard 入口,如何查看輸出,如何使用 keep 設定入口以及使用實體,如何配置壓縮,混淆,校驗等規則。

    ......

    uj5u.com 2020-09-10 06:59:00 more
  • Android 開發技術周報 Issue#292

    新聞 Android即將獲得類AirDrop功能:可向附近設備快速分享檔案 谷歌為安卓檔案管理應用引入可安全隱藏資料的Safe Folder功能 Android TV新主界面將顯示電影、電視節目和應用推薦內容 泄露的Android檔案暗示了傳說中的谷歌Pixel 5a與折疊屏新機 谷歌發布Andro ......

    uj5u.com 2020-09-10 07:00:37 more
  • AutoFitTextureView Error inflating class

    報錯: Binary XML file line #0: Binary XML file line #0: Error inflating class xxx.AutoFitTextureView 解決: <com.example.testy2.AutoFitTextureView android: ......

    uj5u.com 2020-09-10 07:00:41 more
  • 根據Uri,Cursor沒有獲取到對應的屬性

    Android: 背景:呼叫攝像頭,拍攝視頻,指定保存的地址,但是回傳的Cursor檔案,只有名稱和大小的屬性,沒有其他諸如時長,連ID屬性都沒有 使用 cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATIO ......

    uj5u.com 2020-09-10 07:00:44 more
  • Android連載29-持久化技術

    一、持久化技術 我們平時所使用的APP產生的資料,在記憶體中都是瞬時的,會隨著斷電、關機等丟失資料,因此android系統采用了持久化技術,用于存盤這些“瞬時”資料 持久化技術包括:檔案存盤、SharedPreference存盤以及資料庫存盤,還有更復雜的SD卡記憶體儲。 二、檔案存盤 最基本存盤方式, ......

    uj5u.com 2020-09-10 07:00:47 more
  • Android Camera2Video整合到自己專案里

    背景: Android專案里呼叫攝像頭拍攝視頻,原本使用的 MediaStore.ACTION_VIDEO_CAPTURE, 后來因專案需要,改成了camera2 1.Camera2Video 官方demo有點問題,下載后,不能直接整合到專案 問題1.多次拍攝視頻崩潰 問題2.雙擊record按鈕, ......

    uj5u.com 2020-09-10 07:00:50 more
  • Android 開發技術周報 Issue#293

    新聞 谷歌為Android TV開發者提供多種新功能 Android 11將自動填表功能整合到鍵盤輸入建議中 谷歌宣布Android Auto即將支持更多的導航和數字停車應用 谷歌Pixel 5只有XL版本 搭載驍龍765G且將比Pixel 4更便宜 [圖]Wear OS將迎來重磅更新:應用啟動時間 ......

    uj5u.com 2020-09-10 07:01:38 more
  • 海豚星空掃碼投屏 Android 接收端 SDK 集成 六步驟

    掃碼投屏,開放網路,獨占設備,不需要額外下載軟體,微信掃碼,發現設備。支持標準DLNA協議,支持倍速播放。視頻,音頻,圖片投屏。好點意思。還支持自定義基于 DLNA 擴展的操作動作。好像要收費,沒體驗。 這里簡單記錄一下集成程序。 一 跟目錄的build.gradle添加私有mevan倉庫 mave ......

    uj5u.com 2020-09-10 07:01:43 more
最新发布
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:40:31 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:40:11 more
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:39:36 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:39:13 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:16:23 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:16:15 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:15:46 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:14:53 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:14:08 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:08:34 more