Android进阶(二)--序列化Serializable和Parcelabel使用与区别

来源:互联网 发布:淘客cms优惠券 编辑:程序博客网 时间:2024/05/18 03:53

自己之前也做过这方面的疑惑与比较,只是一直没写成文,今天偶尔看到这样一篇不错的文章,重温习下旧知识

转载于:http://blog.csdn.net/simon_crystin/article/details/78553055

1.序列化

1.1 序列化的定义

序列化 (Serialization)将对象的状态信息转换为可以存储或传输的形式的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区。以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。简单地说,“序列化”就是将运行时的对象状态转换成二进制,然后保存到流、内存或者通过网络传输给其他端。

1.2 序列化的使用场景

我们通过Intent传递数据,官方给我们提供了许多的接口,我们可以传递整型,浮点,字符串类型等等,但是我们要传递复杂类型的就不行了,这个时候需要将复杂类型进行序列化

1.3 序列化的方式

  1. 实现Serializable接口(Java);
  2. 实现Parcelable接口(Android)。

1.4 如何选择序列化方式

1)在使用内存的时候,Parcelable比Serializable性能高,所以推荐使用Parcelable。

2)Serializable在序列化和反序列化频繁进行 I/O操作,非常占用内存,在序列化的时候创建许多的临时对象,容易触发垃圾回收,另外使用了反射,序列化的过程较慢。

3)Parcelable不能使用在要将数据存储在磁盘上的情况,因为Parcelable不能很好的保证数据的持续性在外界有变化的情况下。尽管Serializable效率低点,但此时还是建议使用Serializable 。

2.Serializable 接口

Serializable是序列化的意思,表示将一个对象转换成可存储或可传输的状态。序列化后的对象可以在网络或组件上进行传输,也可以存储到本地。

Serializable 是 Java 提供的序列化接口,它是一个空接口:

public interface Serializable {}
  • 1
  • 2

Serilizable序列化很多工作系统都帮我们完成了,我们只需要实现Serializable接口。

2.1 关于Serializable接口

  1. 可序列化类中,未实现 Serializable 的属性状态无法被序列化/反序列化也就是说,反序列化一个类的过程中,它的非可序列化的属性将会调用无参构造函数重新创建, 因此这个属性的无参构造函数必须可以访问,否者运行时会报错。

  2. 一个实现序列化的类,它的子类也是可序列化的;

  3. Serializable有个唯一标识符serialVersionUID,这个serialVersionUID可以我们自己定义,也可以由系统生成,这个标识符是用来确认序列化和反序列化是不是同一个对象,是同一个对象反序列化成功,但是如果当前类有所改变,比如增加或者删除了成员变量,那么系统会重新计算当前类的hash值,赋值给serialVersionUID,发现前后不一样,序列化失败。

serialVersionUID生成方法:

1.Settings->Editor->Inspections->勾选serialVersionUID。
2.当实现Serializable接口,程序会报警告,用快捷键(我的是ALT+Enter)生成serialVersionUID.

这里写图片描述

2.2 Serilizable的实际应用

我们就以在组件Activity传递对象为例;

如何在组件中传递对象,只需要将类实现Serializable接口。

1.新建一个实体类实现Serializable接口;

** * Created by zhangcong on 2017/11/15. * @author zhangcong */public class User   implements Serializable{    private static final long serialVersionUID = 8066301618436107542L;    private String name;    private String password;    public User(String name, String password) {        this.name = name;        this.password = password;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public String getPassword() {        return password;    }    public void setPassword(String password) {        this.password = password;    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

2.在MainActivity序列化;

public class MainActivity extends AppCompatActivity {    private Button button;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        button =findViewById(R.id.bt_click);        button.setOnClickListener(new OnClickListener() {            @Override            public void onClick(View view) {                User user=new User("Simon","222222");                Intent intent=new Intent(MainActivity.this, SerializableActivity.class);                intent.putExtra("Simon",user);                startActivity(intent);            }        });    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

3.在目标activity取出序列化的对象:

public class SerializableActivity extends Activity{    private TextView textView;    @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_common);        textView=findViewById(R.id.tv_text);        Intent intent=getIntent();        User user= (User) intent.getSerializableExtra("Simon");        textView.setText(user.getName()+ "   "+ user.getPassword());    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

3.Parcelable接口

Parcelable 是 Android 特有的序列化接口。

3.1 关于Parcelable接口

Parcelable使用时要用到一个Parcel,可以简单将其看为一个容器,序列化时将数据写入Parcel,反序列化时从中取出。

Parcelable源码:

public interface Parcelable {    int CONTENTS_FILE_DESCRIPTOR = 1;    int PARCELABLE_WRITE_RETURN_VALUE = 1;    //描述当前 Parcelable 实例的对象类型    //比如说,如果对象中有文件描述符,这个方法就会返回上面的 CONTENTS_FILE_DESCRIPTOR    //其他情况会返回一个位掩码    int describeContents();     //将对象转换成一个 Parcel 对象    //参数中 dest 表示要写入的 Parcel 对象    //flags 表示这个对象将如何写入    void writeToParcel(Parcel var1, int var2);    //对象创建时提供的一个创建器    public interface ClassLoaderCreator<T> extends Parcelable.Creator<T> {    //使用类加载器和之前序列化成的 Parcel 对象反序列化一个对象        T createFromParcel(Parcel var1, ClassLoader var2);    }    //实现类必须有一个 Creator 属性,用于反序列化,将 Parcel 对象转换为 Parcelable     public interface Creator<T> {        T createFromParcel(Parcel var1);        T[] newArray(int var1);    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

Parcelable就是通过writeToParcel()方法进行序列化的。序列化的时候讲数据写入Parcel。想要知道Parcelable的原理,就必须弄清楚Parcel是什么?

3.2 Parcel简介:

Parcel翻译过来是打包的意思,其实就是包装了我们需要传输的数据,然后在Binder中传输,也就是用于跨进程传输数据

简单来说,Parcel提供了一套机制,可以将序列化之后的数据写入到一个共享内存中,其他进程通过Parcel可以从这块共享内存中读出字节流,并反序列化成对象,下图是这个过程的模型。

这里写图片描述

Parcel可以包含原始数据类型(用各种对应的方法写入,比如writeInt(),writeFloat()等),可以包含Parcelable对象,它还包含了一个活动的IBinder对象的引用,这个引用导致另一端接收到一个指向这个IBinder的代理IBinder。Parcelable通过Parcel实现了read和write的方法,从而实现序列化和反序列化。

3.3 Parcelable接口使用实例

1.将实体类实现Parcelable接口,我们需要重写几个方法;

/** * * @author zhangcong * @date 2017/11/16 */public class Person implements Parcelable {    private String name;    private int age;    // 系统自动添加,给createFromParcel里面用    protected Person(Parcel in) {        name=in.readString();        age=in.readInt();    }    @Override    public void writeToParcel(Parcel dest, int flags) {        //将数据序列化到对象中        dest.writeString(name);        dest.writeInt(age);    }    @Override    public int describeContents() {        //只针对一些特殊的需要描述信息的对象,需要返回1,其他情况返回0就可以        return 0;    }    public static final Creator<Person> CREATOR = new Creator<Person>() {        @Override        public Person createFromParcel(Parcel in) {            // 反序列化,读取数据            return new Person(in);        }        //供反序列化本类数组时调用的        @Override        public Person[] newArray(int size) {            return new Person[size];        }    };    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public int getAge() {        return age;    }    public void setAge(int age) {        this.age = age;    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60

2.在MainActivity开启序列化

 button2=findViewById(R.id.bt_click2);        button2.setOnClickListener(new OnClickListener() {            @Override            public void onClick(View view) {                Person person=new Person("Simon",23);                Intent intent2=new Intent(MainActivity.this, SerializableActivity.class);                intent2.putExtra("Simon",person);                startActivity(intent2);            }        });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

3.在目标Activity获取对象

Intent intent=getIntent();Person person=intent.getParcelableExtra("Simon");
  • 1
  • 2

4.Serializable 和Parcelable的对比

android上应该尽量采用Parcelable,效率至上。

1.编码上:

Serializable代码量少,写起来方便

Parcelable代码多一些

2.效率上:

Parcelable的速度比高十倍以上。(别人测试过)

至于如何选择前面已经说了,就不赘述了。

5.Github

github
觉得有帮助的话可以star!


阅读全文
0 0
原创粉丝点击