Serialization of data plays an important role in Android development. It is indispensable to support serialization in inter-process communication, local data storage and network data transmission. The selection of appropriate serialization scheme for different scenarios has a great impact on the performance of applications. Broadly speaking, serialization is the process of converting a data structure or object into a data format that can be stored or transmitted. During serialization, a data structure or object writes its state information to a temporary or persistent store. Deserialization is the process of restoring data generated during the serialization process to data structures or objects.

Serializable

The Serializable interface, a feature of the Java language, is one of the simplest and most widely used serialization schemes. Only Java objects that implement the Serializable interface can be serialized. One thing to note here is that the Serializable interface is an identity interface, and Java serializes this object without implementing methods. The disadvantage is that the reflection mechanism is used. Many temporary objects will be created during the serialization process, which is easy to trigger the garbage mechanism. The serialization process is slow, and this scheme is not recommended for scenarios with strict performance requirements.

This is where objects implementing the Serializable interface can be serialized, converting Java objects to byte sequences, and deserialization, which is the process of restoring byte sequences to Java objects.

In the serialized class, serialVersionUID is used to identify the serialized object, that is, only if the serialVersionUID in the serialized data is the same as the serialVersionUID of the current class can be deserialized properly.

import java.io.*;
public class User implements Serializable{
    private static final long serialVersionUID= 123456;
    public int userId;
    public String userName;
    public boolean isMale;
    public User(int userId,String userName,boolean isMale){
        this.userId=userId;
        this.userName=userName;
        this.isMale = isMale;
    }
    public boolean toSerial(User user) throws IOException{
        ObjectOutputStream out=null;
        boolean status=false;
        try{
            out = new ObjectOutputStream(new FileOutputStream("cache.txt"));
            out.writeObject(user);
            status=true;
            }catch(FileNotFoundException e){
                System.out.println("NO FILE");
            }finally{
                if(out! =null)
                    out.close();
            }
        return status;
    }
    public User toObject(String filename) throws IOException{
        ObjectInputStream in=null;
        boolean status=false;
        User user=null;
        try{
            in = new ObjectInputStream(new FileInputStream(filename));
            user=(User) in.readObject();    
        }catch(ClassNotFoundException e){
            System.out.println("No file");
        }finally{
            if(in! =null)
                in.close();
        }
        return user;
    }
    public static void main(String[] args) throws IOException{
        User user = new User(0."jake".true);
        System.out.println(user.toSerial(user));
        System.out.println(user.toObject("cache.txt").getClass()); }}Copy the code

Note: Static member variables belong to classes, not objects, so they obviously do not participate in the serialization of objects. Secondly, the member variables marked with transient keywords do not participate in the serialization process. Finally, this serialization is disk or network based.

Parcelable

Parcelable is provided by the Android SDK. It is based on memory. Since memory reads and writes are faster than hard disk, Parcelable is generally used for cross-process object transfer in Android.

import android.os.Parcel;
import android.os.Parcelable;
public class User implements Parcelable {
    public int userId;
    public String userName;
    public boolean isMale;
    public User(int userId,String userName,boolean isMale) {
        this.userId=userId;
        this.userName=userName;
        this.isMale=isMale;
    }

    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 newUser[size]; }};public User(Parcel in) {
        userId=in.readInt();
        userName = in.readString();
        isMale=in.readInt()==1;
    }

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

    @Override
    public void writeToParcel(Parcel out, int flags) {
        out.writeInt(userId);
        out.writeString(userName);
        out.writeInt(isMale?1:0); }}Copy the code

As you can see from the above, to implement a Parcelable interface, you need to implement the following methods:

  • Constructor: Creates the original object from the serialized object
  • DescribeContents: Specifies the description of an interface. 0 is returned by default
  • WriteToParcel: Serialization method that writes class data to a parcel container
  • Static parcelable.Creator interface, which contains two methods

    • CreateFormParcel: Method of deserialization that restores a Parcel to a Java object
    • NewArray: Provides external classes to deserialize this array.

A comparison of two methods of object serialization

Serializable is a serialization interface in Java, which is simple but expensive to use (Serializable uses reflection during serialization, resulting in a large number of temporary variables, leading to frequent GC), and when reading or writing data, It writes data to the hard disk or transmits it to the network in the form of IO streams.

However, Parcelable uses IBinder as the information carrier and has low overhead in memory. Therefore, it is recommended to use Parcelable when transferring data between memory. However, Parcelable has complex operations in data persistence or network transmission. Serializable is generally recommended at this time.

In addition, Serializable is relatively simple to use, while Parcelable requires manual implementation of interface methods. In order to avoid the trouble of using Parcelable interface, we introduce a plug-in below, so as to automatically generate corresponding code.

After the installation is complete, restart Android Studio for it to take effect, and then write the Java entity class BookItem

public class BookItem {
    public String mName;
    public long mLastTime;
    public String mTitle;
    public String mPath;
}Copy the code

In the Generate interface, click Parceable. The plug-in automatically converts the BookItem class into a form that implements the Parceable interface, saving developers the trouble of manual writing. The generated code is as follows:

public class BookItem implements Parcelable {
    public String mName;
    public long mLastTime;
    public String mTitle;
    public String mPath;

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

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(this.mName);
        dest.writeLong(this.mLastTime);
        dest.writeString(this.mTitle);
        dest.writeString(this.mPath);
    }

    public BookItem() {}protected BookItem(Parcel in) {
        this.mName = in.readString();
        this.mLastTime = in.readLong();
        this.mTitle = in.readString();
        this.mPath = in.readString();
    }

    public static final Parcelable.Creator<BookItem> CREATOR = new Parcelable.Creator<BookItem>() {
        @Override
        public BookItem createFromParcel(Parcel source) {
            return new BookItem(source);
        }

        @Override
        public BookItem[] newArray(int size) {
            return newBookItem[size]; }}; }Copy the code

Serialization scheme for data

The following serialization schemes are generalized. Unlike the previous two narrow or object serialization schemes, the following schemes are for serialization in data transfer and stored procedures.

1.SQLite


SQLite is a lightweight relational database that runs extremely fast and consumes very few resources — typically only a few hundred KILobytes of memory. SQLiteOpenHelper is used to store complex relational data. Android supports SQLite openHelper natively. However, due to the unfriendly native API interface, there are many ORM frameworks that encapsulate SQLite.

2.SharedPreferences


SharedPreferences is a lightweight storage API provided by the Android platform. It is used to store common configuration information. It is essentially a key-value pair storage that supports the storage and reading of common data types such as Boolean, float, int, Long, and String.

Use SharedPreferences to read and store:

1) Get the Sharedpreferences object

SharedPreferences mPreferences = context.getCSharedPreferences(PREFERENCES_NAME, Context.MODE_PRIVATE);Copy the code

2. Use the SharedPReferences object to read the data stored in SharedPReferences

mPreferences.getBoolean(key,defValue);Copy the code

Storage:

1) Get the SharedPreferences.Editor object


SharedPreferences.Editor editor = mPreferences.edit(a);Copy the code

2) Write data to SharedPreferences using the SharedPreferences.Editor object.

mEditor.putBoolean(key,b);Copy the code

3) Call the commit function to commit the written data to complete the data store operation.

mEditor.commit(a);Copy the code

3.JSON


JSON, or JavaSript Object Notation, is a lightweight data interaction format. It is smaller than XML and easier to browse when transmitted over the network. It is widely used on mobile devices. Most apps interact with the server using JSON format.

4. The Protocol Buffers and Nano – Proto – Buffers


Protocol Buffers is a language-independent and platform-independent lightweight and efficient data storage format for serialization structures. Similar to XML, but smaller, faster and simpler, it is suitable for data storage or RPC data exchange. It can be used for communication protocols, data storage and other fields language – independent, platform – independent, extensible serialized structure data format.

The nano-proto-Buffers version should be used on the mobile side. Because ordinary Protocol Buffers generate very verbose code, they can increase the memory footprint of the APP, causing APK to grow in size and degrade performance, and you can quickly run into 64K method limits if you are not careful.

5.FlatBuffers


Google FlatBuffers is an open source, cross-platform, efficient serialization function library created by Google for game development and other performance-sensitive applications. It provides support for C++/Java language interfaces. FlatBuffers is a serialized class library that focuses on performance and resource usage. It is more suitable for mobile devices than Protocol Buffers.

The characteristics of FlatBuffers are as follows:

  • The serialization process does not require packaging and unpacking: FlatBuffers stores serialized data in the cache, which can be stored in a file or transmitted over the network without any additional parsing overhead, in contrast to the unpacking and parsing steps of Protocol Buffers and JSON, for example. The structured data of FlatBuffers are stored in binary format and there is no data parsing process.
  • Low memory footprint and high performance: The only memory requirement for data access is the buffer, and no additional memory allocation is required.
  • Strongly typed system design: As many errors as possible can be found at compile time, rather than waiting until run time to check and fix them manually.
  • Support cross-platform: support C++/Java, etc., do not need other dependent libraries.

FlatBuffers use their special encoding format to reduce memory usage and optimize data read performance. At the same time, the forward and backward compatibility of data structure provides good scalability.