The difference between Serializable and Parcelable

I just saw the source code of Intent today and found that it implements the Parcelable interface. I suddenly remembered that there is a Serializable interface in Java, so I want to take this opportunity to talk about my views on these two interfaces.

In Android, we all know that we cannot directly pass objects to activity. In order to pass objects, these objects must either implement the Serializable interface or the Parcelable interface. So what is the difference between the two? Let's take a look at the Serializable interface first.

Serializable


First look at the definition of the Serializable interface in the Java source code:

package java.io;
public interface Serializable {
}

Serializable is a standard Java interface. From the interface definition, we see that it is located in the java.io package directory. It does not define any methods or variables, and is only used to determine the semantics of serialization. So we can implement this interface and add methods ourselves. But the serialization mechanism uses reflection to construct serialized objects, so the performance is slow. And it creates a large number of temporary objects, which causes a considerable GC. This interface is relatively easy to implement. Let's look at an example:

class SeObject implements Serializable {

    private String name;
    private int age;

    public SeObject(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
}

Here I defined a SeObject, implemented this interface, defined a name and age, and implemented a constructor and getter methods. I plan to pass this SeObject object between activities. Let's take a look at how the first activity passes the SeObject object:

    public void startActivity(View view) {
        Intent intent = new Intent(this, SecondActivity.class);
        SeObject seObject = new SeObject("Leon", 28);
        Bundle bundle = new Bundle();
        bundle.putSerializable("Object", seObject);
        intent.putExtras(bundle);
        startActivity(intent);
    }

First, a Button is defined in the layout of the first activity, and the onClick property is set to startActivity, so that the above method will be called when the Button is clicked. As you can see, I first defined a Bundle, passed the SeObject object into the putSerializable method, put the bundle object into the Intent, and passed it to SecondActivity. Let’s take a look at how SecondActivity.java obtains this SeObject object:

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);

        Intent intent = getIntent();
        Bundle bundle = intent.getExtras();
        SeObject seObject = (SeObject) bundle.getSerializable("Object");
        Log.d("SecondActivity", "Name is " + seObject.getName() + ", age is " +         
             seObject.getAge());
    }

The printed LOG is as follows: 

D/SecondActivity( 7760): Name is Leon, age is 28

Everyone carefully compares the codes of these two files, very careful students should find that there is a corresponding relationship:

putExtras -> getExtras;putSerializable -> getSerializable

When obtaining a SeObject object, first call intent.getExtras() to get the Bundle object, and then call bundle.getSerializable to read the SeObject object from the Bundle object, which is exactly the opposite of the order of putting SeObject objects in the first activity. Remember This sequence is easy to implement in the future to pass custom objects in the Intent, and it is not easy to make mistakes. But after my own verification, the SeObject object can also be obtained in the following way:

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);

        Intent intent = getIntent();
        SeObject seObject = (SeObject) intent.getSerializableExtra("Object");
        Log.d("SecondActivity", "11 Name is " + seObject.getName() + ", age is " + 
             seObject.getAge());
    }

(But I personally like the first implementation method, it is not easy to make mistakes, especially when multiple objects are passed in, you can do it according to your own habits).

Let's look at the Parcelable interface again.

Parcelable


Let us first look at the definition of the Parcelable interface:

package android.os;
public interface Parcelable {
    public void writeToParcel(Parcel dest, @WriteFlags int flags);
    public static final int PARCELABLE_WRITE_RETURN_VALUE = 0x0001;
    public @ContentsFlags int describeContents();
    public interface Creator<T> {
        /**
         * Create a new instance of the Parcelable class, instantiating it
         * from the given Parcel whose data had previously been written by
         * {@link Parcelable#writeToParcel Parcelable.writeToParcel()}.
         * 
         * @param source The Parcel to read the object's data from.
         * @return Returns a new instance of the Parcelable class.
         */
        public T createFromParcel(Parcel source);
        
        /**
         * Create a new array of the Parcelable class.
         * 
         * @param size Size of the array.
         * @return Returns an array of the Parcelable class, with every entry
         * initialized to null.
         */
        public T[] newArray(int size);
    }

I only list a part of the source code here. As you can see from the source code, Parcelable is located in the android.os package directory. It not only defines some variables and methods, but also defines an internal interface Creator<T>. The Parcelable process is much faster than the serialization process. One of the reasons is that we clarified the serialization process instead of using reflection to infer it. The code has been heavily optimized for this. Let's look at an example of Parceable:

class ParObject implements Parcelable {

    private String name;
    private int age;


    public ParObject(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public ParObject(Parcel source) {
        name = source.readString();
        age = source.readInt();
    }

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

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

    public int getAge() {
        return age;
    }

    public String getName() {
        return name;
    }
    
    public static final Creator<ParObject> CREATOR = new Creator<ParObject>() {
        @Override
        public ParObject[] newArray(int size) {
            return new ParObject[size];
        }

        @Override
        public ParObject createFromParcel(Parcel source) {
            return new ParObject(source);
        }
    };

}

Android's Parcelable implementation allows reading and writing from Parcel, and Parcel contains flat data in the message container. If we want to convert Java objects into Parcelable, the best way is to implement the Parcelable interface as above and override the writeToParcel method. The first step is to override the writeToParcel method to write all the members of the object into the parcel object; the second step is to create a static Parcelable.Creator object to achieve deserialization. 

public void startActivity(View view) {    
        ParObject parObject = new ParObject("Leon", 27);
        Intent mIntent = new Intent(this, SecondActivity.class);
        Bundle bundle = new Bundle();
        bundle.putParcelable("object", parObject);
        mIntent.putExtras(bundle);
        startActivity(mIntent);
    }
protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);

        Intent intent = getIntent();
        Bundle bundle = intent.getExtras();
        ParObject parObject = bundle.getParcelable("object");
        Log.d("SecondActivity", "the Name is " + parObject.getName() + ", age is " + 
             parObject.getAge());
    }

The printed log is as follows:

10-26 15:00:58.694 24199 24199 D SecondActivity: the Name is Leon, age is 27

Take a closer look, in fact, the usage is similar to Serializable. The only difference is that putSerializable is replaced by putParcelable, and then it is changed to getParcelable when fetching objects from the second activity.

Someone may ask, is this the difference? Of course not only, since Android provides a more powerful mechanism for transferring objects, it must be able to do more, that is, Parcelable can transfer a list of multiple objects:

public void startActivity(View view) {       
        Intent mIntent = new Intent(this, SecondActivity.class);
        Bundle bundle = new Bundle();
        ArrayList<ParObject> list = new ArrayList<>(2);
        list.add(new ParObject("Leon_1", 27));
        list.add(new ParObject("Leon_2", 28));
        bundle.putParcelableArrayList("object", list);
        mIntent.putExtras(bundle);
        startActivity(mIntent);
    }
protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);

        Intent intent = getIntent();
        Bundle bundle = intent.getExtras();
        ArrayList<ParObject> list = bundle.getParcelableArrayList("object");
        if (list != null) {
            Log.d("SecondActivity", "size is " + list.size());
            for (ParObject parObject : list) {
                Log.d("SecondActivity", "Name is " + parObject.getName() + ", age is " + 
                     parObject.getAge());
            }
        }

    }

The printed log is as follows:

10-26 15:12:28.023 26428 26428 D SecondActivity: size is 2
10-26 15:12:28.023 26428 26428 D SecondActivity: Name is Leon_1, age is 27
10-26 15:12:28.023 26428 26428 D SecondActivity: Name is Leon_2, age is 28

It can be clearly seen that an ArrayList is passed from the first activity, and the List is successfully obtained in the second activity.

Let's check if the bundle provides a List that transmits Serializable objects?

 The answer is: no. Let's take a look at the other interfaces for transferring Parcelable objects:

As you can see, in addition to transmitting List, it can also transmit arrays. This is where Parcelable is more powerful than Serializable.

Summarized as follows:

  1. Compared with serializable, Parcelable takes longer to implement it, that is, write more code
  2. Serializable is easier to implement (there is no method to be copied in the interface)
  3. Serializable uses Java reflection to create a large number of temporary objects during the streaming session, thus causing considerable GC
  4. In Android, you can pass the Parcelable array through Intent
  5. In Parcelable we can write custom code, so it will create less garbage objects, but also because of this custom implementation, it is faster than serializable and has better performance

Guess you like

Origin blog.csdn.net/Xia_Leon/article/details/83278452