Android--serializable & Parcelable

Source: Internet
Author: User

Serializable & Parcelable The two methods of serialization are often used in Android, Serializable is inherited from Java, and Parcelable is the way Android offers itself, Google is recommended to use parcelable, as for the difference between the two methods, the following through the analysis of the source code to slowly understand.

Before analyzing the source code, let's start with the serialization of scenarios used in Android:

1) We use Intente to pass data between the four components, and the data passed in the Intente needs to be serialized.

2) Binder,binder is important in the IPC mechanism, and the data passed in binder is also required to be serialized.

3) Also we often have to persist some data to the storage device, this data needs to be serialized

4) Passing objects in the network


Okay, now we're going to get to the source code of the two serialization modes:


Serializable:

Because serializable is a labeled interface, we mainly read its annotations.


* Marks classes that can is serialized by {@link ObjectOutputStream} and * deserialized by {@link ObjectInputStream}.
This sentence tells us that serializable is through the ObjectOutputStream, ObjectInputStream to complete the serialization process

* <p><strong>Warning:</strong> This interface limits how it implementing * classes can change in the FU Ture. By implementing {@code Serializable} you * expose your flexible in-memory implementation details as a rigid binary * repre Sentation. Simple code changes--like Renaming private Fields--are * isn't safe when the changed class is serializable.
This sentence tells us that there is a code change in the class that implements the Serializable interface, which can cause serialization to fail

<p>every serializable class is assigned a version identifier called a {@code * serialversionuid}. By default, this identifier are computed by hashing the * class declaration and their members. This identifier was included in the * serialized form so, version conflicts can be detected during * deserialization. If The local {@code Serialversionuid} differs from the ' {@code serialversionuid} in the serialized data, deserialization would fail * with an {@link invalidclassexception}. * * <p>you can avoid this failure to declaring an explicit {@code * serialversionuid}. Declaring an explicit {@code Serialversionuid} tells the * serialization mechanism that the class is forward and backward Compatible * with all versions, share that {@code serialversionuid}. Declaring A * {@code serialversionuid} looks like this: <pre> {@code * * private static final long Serialversi Onuid = 0L; *}</pre> * If you declare a {@code serialversionuid}, you should increment it EACH * Time your class changes incompatibly with the previous version. Typically * This is the when you add, the change or remove a non-transient field.

Serialization and deserialization are actually done through Serialversionuid, and by default, Serialversionuid is obtained by hashing the class's member variables and classes. Serialversionuid is stored in a serialized file, when you want to deserialize, you can get serialversionuid from the serialized file, If the obtained Serialversionuid is the same as the Serialversionuid calculated by the member variables and the method hash in the class, the deserialization succeeds, and the result of the deserialization return is not the same object as the serialized result, but the values are the same. If deserialization fails, a incaildclassexception is thrown.

Of course we can also customize the Serialversionuid in the class, for example:

Private static final long serialversionuid = 0L;

The advantage is that when a member variable in a class or method is added, changed, or removed, our deserialization will still succeed, but when the structure of the class changes dramatically, the deserialization fails.

There is a sentence above:

Typically this was when you add, the change or remove a non-transient field.
Tells us that member variables that are modified by transient are not involved in serialization.


* <p>you can take control of your serialized form by implementing these both * methods with these exact signatures in Your serializable classes: * <pre>   {@code * *   private void WriteObject (Java.io.ObjectOutputStream out) *
   throws IOException {*     //write ' This ' to ' out ' ... *   } * *   private void ReadObject (Java.io.ObjectInputStrea M in) *       throws IOException, classnotfoundexception {*//populate the fields of "this" from the data in ' ...     *   } *}</pre>


This note tells us: The default serialization process and deserialization process can be changed, as long as rewrite Wireteobject, readobject these two methods can be, but in general, we will not rewrite these two methods, let us see the default how they are implemented:

First Look at WriteObject:

It is the method in ObjectOutputStream:

    Public final void WriteObject (Object object) throws IOException {        WriteObject (object, False);    }

private void WriteObject (Object object, Boolean unshared) throws IOException {Boolean setoutput = (primitivetypes        = = output);        if (setoutput) {primitivetypes = null; }//This was the specified behavior in JDK 1.2.        Very bizarre behavior overriding.            if (subclassoverridingimplementation &&!unshared) {Writeobjectoverride (object);        Return            } try {//First we need to flush primitive types if they were written drain ();            Actual work, and class-based replacement should is computed//if needed.            Writeobjectinternal (object, unshared, True, true);            if (setoutput) {primitivetypes = output; }} catch (IOException ioEx1) {//This would make it pass through until the top caller.            Only the top caller writes the//exception (where it can). if (Nestedlevels == 0) {try {writenewexception (ioEx1);  } catch (IOException ioEx2) {//If writing the exception to the output stream causes another exception                    There//is no need to propagate the second exception or generate a third exception,                Both of which might obscure details of the root cause. }} throw ioEx1; And then we propagate the original exception}}


This section will determine whether to implement the writeobject in the subclass, if it is implemented, return directly, otherwise it will call
true true);

private int Writeobjectinternal (Object object, Boolean unshared,            boolean computeclassbasedreplacement,            Boolean computestreamreplacement) throws IOException {           ...      F (!) ( Enablereplace && computestreamreplacement)) {                //Is it a Class?                if (objclass = = Objectstreamclass.classclass) {                    return Writenewclass ((class<?>) object, unshared);                }                Is it an ObjectStreamClass?                if (objclass = = Objectstreamclass.objectstreamclassclass) {                    return Writeclassdesc ((ObjectStreamClass) object, unshared);                }            }      "}

In this I only copied some code, like Writenewclass, Wirteclassdesc and a lot of this method, their internal is stored in the output type, in Objectwritten storage objects.

See ReadObject again:

ReadObject is the method in Objectinoutstream:

    Public final Object ReadObject () throws Optionaldataexception,            classnotfoundexception, IOException {        return ReadObject (FALSE);    }
Private Object ReadObject (Boolean unshared) throws Optionaldataexception,            ClassNotFoundException, IOException {      ...     Object result;        try {            //We need this and we can tell when we is returning to the            //original/outside caller            if (++nestedlevel s = = 1) {                //Remember The caller ' s class loader                Callerclassloader = Vmstack.getclosestuserclassloader ( Bootstraploader, Systemloader);            }            result = Readnonprimitivecontent (unshared);            if (restoreinput) {                primitivedata = input;            }        }   ...}
Call Readnonprimitivecontent ();

 Private Object Readnonprimitivecontent (Boolean unshared) throws ClassNotFoundException, IOException {C        Heckreadprimitivetypes ();            if (primitivedata.available () > 0) {optionaldataexception e = new Optionaldataexception ();            E.length = Primitivedata.available ();        Throw e;            } do {byte TC = NEXTTC ();                Switch (TC) {case Tc_class:return readnewclass (unshared);                Case Tc_classdesc:return Readnewclassdesc (unshared);                Case Tc_array:return Readnewarray (unshared);                Case Tc_object:return Readnewobject (unshared);                Case Tc_string:return readnewstring (unshared);                Case Tc_longstring:return readnewlongstring (unshared);                Case Tc_enum:return Readenum (unshared); CASE Tc_reference:if (unshared) {readnewhandle ();                    throw new Invalidobjectexception ("unshared read of Back reference");                } return Readcyclicreference ();                Case Tc_null:return NULL;                    Case Tc_exception:exception exc = readexception ();                throw new Writeabortedexception ("Read an exception", exc);                    Case Tc_reset:resetstate ();                Break                    Case Tc_endblockdata://Can occur reading class annotation PUSHBACKTC ();                    Optionaldataexception e = new Optionaldataexception ();                    E.eof = true;                Throw e;            Default:throw Corruptstream (TC);    }//Only Tc_reset falls through} while (true); }

This is inside a do-while loop, with NEXTTC () to get the types of fields in the input stream, and then get different objects based on the different types.
    Private byte NEXTTC () throws IOException {        if (HASPUSHBACKTC) {            HASPUSHBACKTC = false;//We are consuming it        } else {            //Just in case a later call decides to really push it back,            //We don ' t require the caller to pass it as Parameter            PUSHBACKTC = Input.readbyte ();        }        return PUSHBACKTC;    }

Here input is actually the above output, in the Do-while loop is constantly taken from input, and then get the field, and finally encapsulate the field as an object return, this is the process of deserialization.

Can be seen in the serialization of a large number of i\o operations, but also useful to the reflection of the mechanism, the consumption of resources is also relatively large

Parcelable:

The usual, look at the annotations first:

* Interface for classes whose instances can is written to * and restored from a {@link Parcel}.  Classes implementing the Parcelable * interface must also have a static field called <code>creator</code>, whi CH * is an object implementing the {@link Parcelable.creator parcelable.creator} * interface.
This means that objects can be serialized and deserialized through parcel, and it is important to have a member variable in the implementation parcelable, and to be decorated with a static field, The type is parcelable.creator, which is an internal interface in the Parcelable

<p>a Typical implementation of parcelable is:</p> *  * <pre> * public class Myparcelable implements P arcelable {*     private int mdata; * Public     int describecontents () {*         return 0; *     } * * Public     void W Ritetoparcel (Parcel out, int flags) {*         out.writeint (mdata); *     } * Public     static final PARCELABLE.CREATOR&L T Myparcelable> CREATOR *             = new parcelable.creator<myparcelable> () {* Public         myparcelable Createfromparcel (Parcel in) {*             return new myparcelable (in), *         } * * Public         myparcelable[] NewArray (int si Ze) {*             return new myparcelable[size]; *         } *     }; *      *     private myparcelable (Parcel in) {*         mDa Ta = In.readint (); *     } *}</pre>

This note is an example of what Android gives us, because parcelable is more complex than serializable, and may be in this consideration, give us an example, does bring us some benefits, we do not have to be so deliberately to remember, when the use of the time to see the source is OK!

public static final int contents_file_descriptor = 0x0001;        /**     * Describe The kinds of special objects contained in this parcelable ' s     * marshalled representation.     *       * @return A bitmask indicating the set of special object types marshalled     * by the parcelable.     *    /public int describecontents ();    
A file descriptor that returns 1 (contents_file_descriptop) When the object has a file descriptor, or 0, which in most cases returns 0

/**     * Flatten This object with to a Parcel.     *      * @param dest the Parcel in which the object should is written.     * @param the flags Additional flags about how the object should is written.     * May is 0 or {@link #PARCELABLE_WRITE_RETURN_VALUE}.     *    /public void Writetoparcel (Parcel dest, int flags);
The method is to write the object into the serialization structure, dest: The container of the serialized structure that the object should be written to

Flags: There are two kinds of results, 1 (parcelable_write_return_value) from the literal meaning You can see that it is required to return an object, and in most cases it is 0.


/**     * Interface that must is implemented and provided as a public CREATOR     * field that generates instances of your Parcelable class from a Parcel.     */Public    interface Creator<t> {}

This is the internal interface in Parcelable, which is to construct an instance of the class that implements the parcelable from a parcel, that is, the process of taking the deserialization.

Then look at the two interfaces in creator:

        /**         * Create A new instance of the Parcelable class, instantiating it         * from the given Parcel whose data had Previ ously 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);
The method is to construct an instance of the class that implements the parcelable from the parcel, which is usually implemented through the constructor of the class:

return new T (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);

Creates an array of the original objects of a specified length, which we typically return directly:

return new T[size];

The implementation of serialization and deserialization in parcelable is accomplished primarily through parcel, and for parcel, it is possible to see

parcel mechanism in Android (top)


Finally, a summary:



Advantages Disadvantages
Serializable 1) simple to implement.
2) through custom Serialversionuid
Can reduce the occurrence of deserialization failures
1) Reflection
2) Large number of i\o operations, slow deserialization
2) Cost source
Parcelable 1) Fast speed 1) difficult to read and difficult to achieve
2) Difficult to maintain
As for which mode of serialization to choose, it is also necessary to choose.


Finally, thank you all for watching!

Android--serializable & Parcelable

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.