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

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

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

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


}

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());


    }
}

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 对象
    //参数中 var1表示要写入的 Parcel 对象
    //var2表示这个对象将如何写入
    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);
    }
}

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

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

3.在目标Activity获取对象

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

4.Serializable 和Parcelable的对比

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

1.编码上:

Serializable代码量少,写起来方便

Parcelable代码多一些

2.效率上:

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

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

5.Github

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

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AnjoyZhang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值