Android中Intent/Bundle的通信原理及大小限制(Parcelable原理及與Serializable的區別)

我們知道可以通過Intent和bundle在activity或fragment間進行通信,那麼這個通信是如何實現的。
通過intent的bundle的源碼可以看到它們都是實現了Parcelable,其實就是通過序列化來實現通信的。

提到Parcelable就不得不提Serializable,這裏引用一段網上的總結:
介紹Parcelable不得不先提一下Serializable接口,Serializable是Java爲我們提供的一個標準化的序列化接口,那什麼是序列化呢? —- 簡單來說就是將對象轉換爲可以傳輸的二進制流(二進制序列)的過程,這樣我們就可以通過序列化,轉化爲可以在網絡傳輸或者保存到本地的流(序列),從而進行傳輸數據 ,那反序列化就是從二進制流(序列)轉化爲對象的過程.



Parcelable是Android爲我們提供的序列化的接口,Parcelable相對於Serializable的使用相對複雜一些,但Parcelable的效率相對Serializable也高很多,這一直是Google工程師引以爲傲的,有時間的可以看一下Parcelable和Serializable的效率對比 Parcelable vs Serializable 號稱快10倍的效率

Parcelable的底層使用了Parcel機制。傳遞實際上是使用了binder機制,binder機制會將Parcel序列化的數據寫入到一個共享內存中,讀取時也是binder從共享內存中讀出字節流,然後Parcel反序列化後使用。這就是Intent或Bundle能夠在activity或者跨進程通信的原理。(參考“探索startActivity流程及在Activity間是如何傳遞Intent的”)


關於Parcelable和Serializable的區別,同樣引用一段網上的總結:
Parcelable和Serializable的區別和比較
Parcelable和Serializable都是實現序列化並且都可以用於Intent間傳遞數據,Serializable是Java的實現方式,可能會頻繁的IO操作,所以消耗比較大,但是實現方式簡單 Parcelable是Android提供的方式,效率比較高,但是實現起來複雜一些 , 二者的選取規則是:內存序列化上選擇Parcelable, 存儲到設備或者網絡傳輸上選擇Serializable(當然Parcelable也可以但是稍顯複雜)



這樣我們瞭解了Intent/Bundle的通信原理,但是使用時我們經常會遇到數據過大的問題,一般我們都知道intent不能傳輸大數據,這個限制是1MB,那麼是什麼或在哪裏限制了呢?
當我們用Intent傳輸過大數據時,一般logcat會報出TransactionTooLargeException錯誤,谷歌官方對這個錯誤的描述如下:
The Binder transaction failed because it was too large.
During a remote procedure call, the arguments and the return value of the call are transferred as
Parcel objects stored in the Binder transaction buffer. If the arguments or the return value are too
large to fit in the transaction buffer, then the call will fail and TransactionTooLargeException
will be thrown.

The Binder transaction buffer has a limited fixed size, currently 1Mb, which is shared by all
transactions in progress for the process. Consequently this exception can be thrown when there
are many transactions in progress even when most of the individual transactions are of moderate size.

There are two possible outcomes when a remote procedure call throws TransactionTooLargeException.
Either the client was unable to send its request to the service (most likely if the arguments were
too large to fit in the transaction buffer), or the service was unable to send its response back to
the client (most likely if the return value was too large to fit in the transaction buffer). It is
not possible to tell which of these outcomes actually occurred. The client should assume that a
partial failure occurred.

The key to avoiding TransactionTooLargeException is to keep all transactions relatively small.
Try to minimize the amount of memory needed to create a Parcel for the arguments and the return
value of the remote procedure call. Avoid transferring huge arrays of strings or large bitmaps.
If possible, try to break up big requests into smaller pieces.

If you are implementing a service, it may help to impose size or complexity contraints on the
queries that clients can perform. For example, if the result set could become large, then don't
allow the client to request more than a few records at a time. Alternately, instead of returning
all of the available data all at once, return the essential information first and make the client
ask for additional information later as needed.



簡單來說,我們上面提到了Parcel機制使用了一個共享內存,這個共享內存就叫Binder transaction buffer,這塊內存有一個大小限制,目前是1MB,而且是共用的,當超過了這個大小就會報錯。
也就是說不僅僅是一次性傳遞大數據會出問題,當同時傳遞很多數據,儘管每個都不超過1MB,但是總大小超過1MB也會出錯。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章