Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does retrieving a parcelable object through bundle always create new copy?

I'm passing a parcelable object to a fragment by adding into a bundle while creating the fragment. In onc instance modification to this parcelled object reflects modification in original object and in another case it is not. I'm a little baffled by this behaviour. Till now I have assumed retrieving a parcelled objects through a bundle always create new object[no sure whether it's shallow copy or deep copy].

Someone please clarify parcelable behaviour.

like image 330
apersiankite Avatar asked Oct 07 '16 11:10

apersiankite


People also ask

Are bundles Parcelable?

Bundle is a container for named values of types standard for android (including Parcelable ), which is used to pass data between activies, fragments and other android app entites.

Why Parcelable is faster than serializable?

Parcel able is faster than serializable. Parcel able is going to convert object to byte stream and pass the data between two activities. Writing parcel able code is little bit complex compare to serialization. It doesn't create more temp objects while passing the data between two activities.

What is a primary purpose of the Parcelable interface?

The Parcelable interface adds methods to all classes you want to be able to transfer between activities. These methods are how parcelable deconstructs the object in one activity and reconstructs it in another.

What is the difference between Serializable and Parcelable which is the best approach in Android?

Serializable is a standard Java interface. You simply mark a class Serializable by implementing the interface, and Java will automatically serialize it in certain situations. Parcelable is an Android specific interface where you implement the serialization yourself.


1 Answers

I was struggling with a similar issue. At the first glance it seems that we always obtain a new deep copy from the parcelled objects. Moreover, there are even some StackOverflow answers which suggest to use Parcelable interface to clone objects. All this just increases confusion regarding the subject.

Here is what I've found after a lot of searching and googling:

  • Take a closer look at the official Parcel documentation. Here is the important quote:

An unusual feature of Parcel is the ability to read and write active objects. For these objects the actual contents of the object is not written, rather a special token referencing the object is written. When reading the object back from the Parcel, you do not get a new instance of the object, but rather a handle that operates on the exact same object that was originally written.

Ok, as you can see, there are some special objects that are not being copyed during unparceling. But this is still a bit confusing. Does it mean we have another strong reference to the original object which prevents its garbage collection? And what are the use-cases for such objects?

  • To answer the aforementioned questions I decided to look through the Android source code. The methods I was looking for are readStrongBinder and writeStrongBinder which according to the docs do not cause a new object creation when the parcels are sent/received. And I think I found the desired answer in the ResultReceiver.java class. Here is the interesting line:

    mReceiver = IResultReceiver.Stub.asInterface(in.readStrongBinder());
    

    To understand what is this line actually doing we should go to the official AIDL documentation. Here are the most important parts:

The steps a calling class must take to call a remote interface defined with AIDL:
...
5. In your implementation of onServiceConnected(), you will receive an IBinder instance (called service). Call YourInterfaceName.Stub.asInterface((IBinder)service) to cast the returned parameter to YourInterface type.

A few comments on calling an IPC service:

Objects are reference counted across processes.

So let's put all things together:

  1. The parcelled objects can be extracted without involving deep copy process.
  2. If the parcelled objects are read using readStrongBinder method no new instances are being created. We just objtain a new reference to the original object and this reference can prevent its dealllocation.
  3. To know whether our object will be deep copyed after the parcel has been received we should take a closer look at the concrete Parcelable interface implementation.
  4. Android documentation can be really confusing and it may take a lot of time to understand it correctly.

Hope this info will help you.

If you want to read about a real-world example when the confusion regarding Parcelable objects can cause serious problems check out my blog post.

like image 127
Stan Mots Avatar answered Oct 19 '22 03:10

Stan Mots