Android 序列化

Android 在传递数据时,我们一般使用的是Intent的putExtra()方法来传递数据,但是putExtra()方法所支持的数据类型是有限的,只支持一些常用的数据类型,比如 int,String等。当我们想传递一些自定义的对象的时候,就需要用其他的方式来处理,Android使用Intent来传递对象数据通常有两种实现方式:SerializableParcelable
本文介绍一下这两种方式的使用方法

Serializable

Serializable是表示将一个对象转换成可存储或可传输的状态,这就是数据的序列化。序列化后的对象可以在网络上进行传输,也可以存储到本地。比如我们定义一个Book类,其中包含bookName和price两个字段,将他序列化只需要让Book类去实现Serializable接口,这样所有的Book对象就是可序列化的了:

public class Book implements Serializable {

    private String bookName;
    private long price;

    public String getBookName() {
        return bookName;
    }

    public void setBookName(String bookName) {
        this.bookName = bookName;
    }

    public long getPrice() {
        return price;
    }

    public void setPrice(long price) {
        this.price = price;
    }

}
在Book类中实现set和get方法,用于对字段数据的赋值和取值,Book类实现了Serializable接口

类之间的数据传递

接下来我们在类中对Book类进行数据的传递,如下:

    Book book = new Book();
    book.setBookName("java");
    book.setPrice((long) 59.0);
    Intent intent = new Intent(this,OtherActivity.class);
    intent.putExtra("book_data",book);
    startActivity(intent);

由于Book实现了Serializable接口,所以在这里我们直接将它传入到putExtra()方法中,通过Intent传递,然后我们在OtherActivity类中获取这个对象,取出我们传递过来的数据。

 Intent intent = getIntent();
 Book book = (Book) intent.getSerializableExtra("book_data");
 Log.i(TAG,"bookName :"+book.getBookName());
 Log.i(TAG,"price :"+book.getPrice());

这里我们调用了getSerializableExtra()方法来获取通过参数传递过来的序列化的对象,接着再将它转换成Book对象,这样就实现的自定义对现的数据传递的功能。

将序列化的对象存储到本地

序列化的对象存储到本地,只需要采用ObjectOutputStreamObjectInputStream即可轻松实现对象的本地存储
代码:
存储本地:

    try {
        Book book = new Book();
        book.setBookName("java");
        book.setPrice((long) 59.9);
        //序列化的过程
        ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream(getExternalCacheDir()+"/cache.txt"));
        outputStream.writeObject(book);
        outputStream.close();
    } catch (IOException e) {
        e.printStackTrace();
    }

本地取出数据:

   try {
        //反序列化的过程
        ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream(getExternalCacheDir()+"/cache.txt"));
        Book newBook = (Book) inputStream.readObject();
        Log.i("OtherActivity","bookName :"+newBook.getBookName());
        Log.i("OtherActivity","price :"+newBook.getPrice());
        inputStream.close();
    } catch (IOException e) {
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }

在序列化过程中,我们可以声明一个SerialVersionUID,这个SerialVersionUID也不是必须声明的,这个SerialVersionUID是用来辅助序列化和反序列化过程的,原则上序列化的数据中的SerialVersionUID只有和当前类的SerialVersionUID相同才能够正常的反序列化,SerialVersionUID的详细工作机制是:序列化的时候系统会把当前类的SerialVersionUID写入序列化的文件中,当反序列化的时候系统会去检测文件中的SerialVersionUID,看它是否和当前的类SerialVersionUID一致,如果一致就说明序列化的类的版本和当前类的版本基本相同,这个时候可以成功反序列化,否则就说明当前类和序列化的类相比发生了某些变化,比如成员变量的数量,类型可能发生了变化,这个时候是无法正常反序列化的。所以,我们一般手动指定SerialVersionUID的值,也可以让IDE根据当前类的结构自动生成,这样序列化和反序列化的SerialVersionUID是相同的,就可以正常的进行反序列化。

Parcelable

Parcelable也是一个接口,我们只要实现这个接口,一个类的对象就可以实现序列化并可以通过Intent和Binder传递,我们看下具体的实现方法:

public class Person implements Parcelable {

    private String name;
    private int age;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public static final Creator<Person> CREATOR = new Creator<Person>() {
        /*从序列化后的对象中创建原始对象*/
        @Override
        public Person createFromParcel(Parcel in) {
            //这个读取数据的顺序一定要和刚才写出的顺序完全相同
            Person person = new Person();
            person.name = in.readString();//读取name
            person.age = in.readInt();//读取age
            return person;
        }

        //创建指定长度的原始对象数组
        @Override
        public Person[] newArray(int size) {
            return new Person[size];
        }
    };

    //返回当前对象的内容描述,含有文件描述符,返回1,否则返回0,几乎所有情况都返回 0
    @Override
    public int describeContents() {
        return 0;
    }

    /*
     *  将当前对象写入序列化结构中,其中flags标识有两种值 0和1
     *  为1时表示当前对象需要作为对象返回值返回,不能立即释放资源,几乎所有情况都为0
     */
    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(name);//写出name
        dest.writeInt(age);//  写出age
    }
}

通过Parcelable序列化的类,我们可以使用相同的代码来传递Person类

    Person person = new Person();
    person.setName("张三");
    person.setAge(20);
    Intent intent = new Intent(this,OtherActivity.class);
    intent.putExtra("person_data",person);-
    startActivity(intent);

获取传过来的值,我们需要使用getParcelableExtra()方法:

    Intent intent = getIntent();
    Person person = (Person) intent.getParcelableExtra("person_data");
    Log.i("OtherActivity","Name :"+person.getName());
    Log.i("OtherActivity","age :"+person.getAge());

Serializable和Parcelable对比

Serializable和Parcelable都能实现序列化并且都可用于Intent间的数据传递,他们之间有什么区别呢?

  • Serializable是java中的序列化接口,会把整个对象进行序列化,序列化和反序列化需要大量的I/O操作,因此效率会比Parcelable方式低一些。
  • Parcelable是Android中的序列化方式,他的效率更高,这是android推荐的序列化方式。Parcelable主要用在内存序列化上,也可以通过Parcelable将对象序列化到存储设备中或者将对象序列化后通过网络传输,但这个过程会稍显复杂,因此推荐在这两种情况下使用serializable。

猜你喜欢

转载自blog.csdn.net/zhu522959034/article/details/79474820