编程知识 cdmana.com

Android serialization problems and thinking

Let's talk about Android Object serialization in , How much do you know ?

What serialization means ? What's the usage?

serialize It means that the objects become orderly Byte stream , After it becomes a byte stream, a series of operations such as transfer and storage can be carried out .
Deserialization It's serialized Do the opposite , In other words, the bytes generated by serialization are transferred to objects in our memory .

introduce Android There are two serialization interfaces in

Serializable

yes Java A serialization interface provided , Is an empty interface , Provides serialization and deserialization operations specifically for objects . The specific use is as follows :

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;
    }
}

Realization Serializable Interface , Make a statement serialVersionUID.

Someone may have asked here , Not ah , I don't usually have this serialVersionUID ah . you 're right ,serialVersionUID It's not necessary , Because if you don't write , The system will automatically generate this variable . What's the use of it ? When serializing , The system will put the current class serialVersionUID Write to the serialized file , This will be detected when deserializing serialVersionUID, See if he's with the current class serialVersionUID Agreement , The same can be deserialized normally , If it's not the same, you'll get a wrong report .

So this serialVersionUID It is an identifier in the process of serialization and deserialization , For consistency . What effect would it have if we didn't add it ? If we serialize , Changed some member variables of this class , that serialVersionUID Will change , At this time, if you take the previously serialized data to deserialize, an error will be reported . So if we manually specify serialVersionUID To ensure maximum recovery of data .

Serializable In fact, the essence of is to put Java Objects are serialized into binary files , And then you can pass... Between processes , And for network transmission or local storage and other operations , Because of its nature, it stores files . You can look at the source code :


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();
            
            // Writing binary files , Magic numbers at the beginning of ordinary objects 0x73
            bout.writeByte(TC_OBJECT);
            // Write the descriptor of the corresponding class , See the bottom of the source code 
            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() {
        //  If there is no definition serialVersionUID, The serialization mechanism will call a function to calculate a hash value 
        if (suid == null) {
            suid = AccessController.doPrivileged(
                new PrivilegedAction<Long>() {
                    public Long run() {
                        return computeDefaultSUID(cl);
                    }
                }
            );
        }
        return suid.longValue();
    }

You can see that it is through reflection to get information about the object and its properties , And then write the data to a Binary , And write the serialization protocol version and so on .
And get ·serialVersionUID· The logic is also reflected , If id If it is empty, a calculation will be generated hash value .

Parcelable

Android The interface that comes with it , It's a lot of trouble to use : Need to achieve Parcelable Interface , rewrite describeContents(),writeToParcel(Parcel dest, @WriteFlags int flags), And add a static member variable CREATOR And implement Parcelable.Creator Interface

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) , Represents the creation of the original object from a serialized object
  • newArray, Represents the creation of an array of original objects of a specified length
  • writeToParcel, Represents writing the current object to the serialization structure .
  • describeContents, Represents the return of the content description of the current object . If there are file descriptors , return 1, Otherwise return to 0.

Parcelable Is stored through Parcel Stored in memory , In short ,Parcel Provides a mechanism , The serialized data can be written to a shared memory , Other processes go through Parcel You can read the byte stream from this shared memory , And anti sequenced into objects .

This is actually through native Method . I didn't analyze the specific logic , If you have a god friend, you can analyze it in the comments section .

Of course ,Parcelable It's also persistent , involves Parcel Medium unmarshall and marshall Method . Just post the code here :

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 = parcel.readParcelable(ParceData.class.getClassLoader());
            fis.close();

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

summary

0) The difference between the two , How should we choose ?

Serializable yes Java The provided serialization interface , It's easy to use but expensive , Both serialization and deserialization require a large number of I/O operation .
Parcelable yes Android Provided in , It's also Android The serialization method recommended in . Although it is troublesome to use , But it's very efficient .

therefore , If it's memory serialization level , So it's still suggested that Parcelable, Because he will be more efficient .
If it's network transmission and storage disk situation , Just recommend Serializable, Because serialization is relatively simple , and Parcelable There is no guarantee , The continuity of data when external conditions change .

1) For memory serialization, it is recommended to use Parcelable, Why? ?

  • because Serializable It's storing a binary file , So there will be frequent IO operation , The consumption is also relatively large , And it uses a lot of reflection , Reflection operations are also time-consuming . by comparison Parcelable It's going to be a lot more efficient .

2) For data persistence, it is recommended to use Serializable, Why? ?

  • First ,Serializable Itself is stored in a binary file , So it's easier to use persistence . and Parcelable Serialization is an in memory operation , If the process is shut down or restarted , The data in memory will disappear , that Parcelable Serialization is used for persistence, and it may fail , That is, the data will not be continuous and complete . and Parcelable Another problem is compatibility , Every Android Versions may have different internal implementations , Knowledge used in memory, that is to transfer data, does not affect , But if you persist, there may be problems , Compatibility problems may occur when the lower version of data is obtained from the higher version . So it's better to use Serializable persist .

3)Parcelable Certain ratio Serializable Fast ?

  • An interesting example is : When serializing a super large object graph ( Represents through an object , Have access to many other objects through a certain path ), And each object has 10 More than attributes , also Serializable Realized writeObject() as well as readObject(), On average, on every Android device ,Serializable The serialization speed is greater than Parcelable 3.6 times , The speed of deserialization is greater than 1.6 times .

The specific reason is because Serilazable In the way of realization , There is a concept of caching , When an object is parsed , Will be cached in HandleTable in , The next time you resolve to an object of the same type , Then you can go to the binary stream , Write the corresponding cache index . But for Parcel Come on , There is no such concept , Each serialization is independent , Every object , Treat as a new object and a new type of way .

Reference resources

Parcelable

Bye-bye

You can pay attention to it if you have a partner to study together ️ My public number —— Put blocks on it , Analyze one knowledge point every day , We accumulate knowledge together .

版权声明
本文为[Pause]所创,转载请带上原文链接,感谢

Scroll to Top