Android process communication-serialization of Serialzable and Parcelable

Introduction to serialization

definition

Serialization is the process of converting the state information of an object into a form of storage or transmission . During serialization, the object writes its current state to temporary or persistent storage. Later, you can recreate the object by reading or deserializing the state of the object from the storage area.
Write picture description here

Simply put:
serialization is the conversion of an object into a byte stream.
Deserialization is the conversion of a byte stream into an object.

use

The main purpose:

  • Serialization writes objects into byte streams and stores them in memory, files, and databases persistently
  • Transfer serialized objects to other clients over the network

In Android development, the objects of Intent, Bundle and Binder all need to be serialized during data transmission. example:

ublic Intent putExtra(String name, Parcelable value) {...}
public Intent putExtra(String name, Serializable value) {...}

There are two ways to serialize in Android

  • Serializable interface
  • Parcelable interface

Serializable interface

The Serializable interface is an empty serialization interface provided by java. The serialization process is also very simple. You only need to implement the Serializable interface:

//空接口
public interface Serializable {

}

public class User implements Serializable{

    private String userName;
    private String userId;

    public String getUserName() {
        return userName;
    }
    public void setUserName(String userName) {
        this.userName = userName;
    }
    public String getUserId() {
        return userId;
    }
    public void setUserId(String userId) {
        this.userId = userId;
    }
}



Implementation of serialization and deserialization of an object:

  • Use ObjectOutputStream for object serialization
  • Use ObjectInputStream byte stream to deserialize into an object

Why use ObjectOutputStream for serialization and ObjectInputStream for deserialization? In fact, it can be understood like this (personal understanding, easy to remember)

The core functions of the plant is the production of products, a product compared to an object, when to produce a certain product, you need to purchase materials from outside into the cargo ( the Input ); to complete the production of the product at this time need the goods ( the Output ) to In the hands of the customer.
Summary:
Object: Object
Object Serialization: Shipment (Output)
Deserialization into Object: Purchase (Input)

example:

  /**
     * 序列化
     */
    public synchronized static boolean saveUser(User user,String path){

        try {
            File file = new File(path);
            //判断文件是否存在
            if (file.exists()){
                //删除
                file.delete();
            }
            //创建文件
            file.createNewFile();
            FileOutputStream fileOutputStream = new FileOutputStream(path);
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
            objectOutputStream.writeObject(user);
            objectOutputStream.close();
          return true;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return false;
    }


    /**
     * 反序列化
     */
    public synchronized static User getUser(String path){
        try {

            FileInputStream fileInputStream = new FileInputStream(path);
            ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
            User user = (User) objectInputStream.readObject();
            objectInputStream.close();
            return user;
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }


 public void onClick(View view) throws IOException {
        String path = Environment.getExternalStorageDirectory() + "/" + "user.txt";
        switch (view.getId()){
            case R.id.but_serialization:
                //序列化
                User user = new User();
                user.setUserName("张三");
                user.setUserId("11");
                boolean saveUser = saveUser(user,path);
                Log.i(TAG,"序列化是否成功:"+saveUser);
                break;
            case R.id.but_deserialization:
                //反序列化
                User user1 = getUser(path);
                if (user1==null) return;
                Log.i(TAG,user1.getUserName()+"--"+user1.getUserId());
                break;

        }
    }

Output result:
Write picture description here

In fact, there is another very important parameter when using Serializable serialization: serialVersionUID, which is a random number, which will affect the deserialization process.
Its function is to prevent the version number of the serialized write file of the class from being inconsistent with the version number of the deserialized class, causing the program to crash, and the final deserialization fails.
When a class uses Serializable serialization, if the serialVersionUID value is not manually set, in fact, a warning will be prompted on the IDE:
Write picture description here

The above example does not set the serialVersionUID (there is no serialVersionUID by default), we can add or delete a field in the User class, and then deserialize to see what the result is.

public class User implements Serializable{

    private String userName;
    private String userId;
    private String sex;

Write picture description here
Write picture description here
From the log, the deserialization did not succeed, an InvalidClassException error was reported , and the serialVersionUID value in our serialization and deserialization was different.
Since serialVersionUID is inconsistent and causes serialization to fail, then we set a serialVersionUID value for the User class, after re-serialization, delete or add a variable, and finally look at the result of deserialization.
The method to quickly and automatically generate serialVersionUID on the code: place the cursor on the class, select the class name, Alt+Enter will pop up a prompt, and then import directly to complete.
Write picture description here

public class User implements Serializable{

    private static final long serialVersionUID = 1536609946676788617L;
    private String userName;
    private String userId;
 }

In the end, you will find that the deserialization can be successful, and there will be no deserialization failure due to adding or deleting a field.

Parcelable interface

The Parcelable interface is a unique serialization method for Android. The source code is as follows:

public interface Parcelable {
    //writeToParcel() 方法中的参数,用于标识当前对象作为返回值返回
    //有些实现类可能会在这时释放其中的资源
    public static final int PARCELABLE_WRITE_RETURN_VALUE = 0x0001;

    //writeToParcel() 方法中的第二个参数,它标识父对象会管理内部状态中重复的数据
    public static final int PARCELABLE_ELIDE_DUPLICATES = 0x0002;

    //用于 describeContents() 方法的位掩码,每一位都代表着一种对象类型
    public static final int CONTENTS_FILE_DESCRIPTOR = 0x0001;

    //描述当前 Parcelable 实例的对象类型
    //比如说,如果对象中有文件描述符,这个方法就会返回上面的 CONTENTS_FILE_DESCRIPTOR
    //其他情况会返回一个位掩码
    public int describeContents();

    //将对象转换成一个 Parcel 对象
    //参数中 dest 表示要写入的 Parcel 对象
    //flags 表示这个对象将如何写入
    public void writeToParcel(Parcel dest, int flags);

    //实现类必须有一个 Creator 属性,用于反序列化,将 Parcel 对象转换为 Parcelable 
    public interface Creator<T> {

        public T createFromParcel(Parcel source);

        public T[] newArray(int size);
    }

    //对象创建时提供的一个创建器
    public interface ClassLoaderCreator<T> extends Creator<T> {
        //使用类加载器和之前序列化成的 Parcel 对象反序列化一个对象
        public T createFromParcel(Parcel source, ClassLoader loader);
    }
}

Parcel is a packaging class that packs serializable data inside and plays an intermediate conversion role in serialization and deserialization.

public class User2 implements Parcelable{
    private String userName;
    private String userId;
    private List<Book> mBooks;
    private static class Book{

   }

    /**
     * 1、当前对象的内容描述
     * @return 一般返回0
     */
    @Override
    public int describeContents() {
        return 0;
    }

    /**
     * 2、将对象写入序列化结构中(序列化)
     * @param dest
     * @param flags 0或1 ,一般为0,1表示不能立即释放资源
     */
    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(this.userName);
        dest.writeString(this.userId);
        dest.writeList(this.mBooks);
    }

    public User2() {
    }
    
    /**
     * 反序列化
     */
    public static final Creator<User2> CREATOR = new Creator<User2>() {

        /**
         * 反序列化类对象
         * @param source
         * @return
         */
        @Override
        public User2 createFromParcel(Parcel source) {
            return new User2(source);
        }

        /**
         * 反序列化成数组
         * @param size
         * @return
         */
        @Override
        public User2[] newArray(int size) {
            return new User2[size];
        }
    };

    /**
     * 使用反序列的Parcel进行取值
     * @param in
     */
    protected User2(Parcel in) {
        this.userName = in.readString();
        this.userId = in.readString();
        this.mBooks = new ArrayList<Book>();
        in.readList(this.mBooks, Book.class.getClassLoader());
    }
}

In AS, you can use plug-ins to automatically generate Parcelable implementation code.
Write picture description here

to sum up

Both Serializable and Parcelable can achieve serialization for data transfer. Serializable only needs to implement the interface (set the serialVersionUID value of the insurance point), while the implementation of serialization using Parcelable is relatively complicated. When the efficiency is higher than that of Serializable, the bottom layer of Android has been optimized accordingly.

Save to SD card, database or network transmission generally use Serializable serialization, although the efficiency is lower, but it is very convenient to use.
It is recommended to use Parcelable for data transfer between Intent, Bundle, and Binder. Android has optimized memory serialization in this area, which is highly efficient.

reference

Android development art exploration
https://blog.csdn.net/u011240877/article/details/72455715
https://blog.csdn.net/lixiang_Y/article/details/54946199?locationNum=2&fps=1
https://blog. csdn.net/u011240877/article/details/72455715

Guess you like

Origin blog.csdn.net/hzw2017/article/details/80978663