Android中序列化

来源:互联网 发布:python sleep用法 编辑:程序博客网 时间:2024/05/22 22:47

(一)Serializable

Android应用是用java开发,那么java序列化Serializable也是可以使用的,java序列化优点是使用简洁,开销较大,适合用用于存取到设备上 如SD卡等。

把需要序列化数据类接入Serializable接口就可以了,如果有不想序列化的数据还可以用 transient 来取消这个变量的序列化。代码如下:


package com.xue.qin.demo.myserialization;import java.io.Serializable;/** * Created by xue.qin on 2017/6/5. */public class MyObject implements Serializable {    private int n;    private String name;    transient String useless;    public MyObject(int n, String name, String useless) {        this.n = n;        this.name = name;        this.useless = useless;    }    @Override    public String toString() {        return "( n:" + n + " name:" + name + " useless:" + useless + " 地址:" + super.toString()+" )";    }}


在看java的时候发现一个有意思的事情,对象网,当一个对象引用obj1指向另一个对象obj2的时候,如果序列化分别写入,再读取出来,这两个的地址会不会还是统一的。如下代码做的实验。

MyObject obj1, obj2, obj3;        MyObject obj4, obj5, obj6;        try {            obj2 = new MyObject(1, "dog","here");            obj1 = obj2;            obj3 = new MyObject(2, "cat","there");            Log.i(TAG, "写入的对象\n");            Log.i(TAG, "obj1 = " + obj1 + " ");            Log.i(TAG, "obj2 = " + obj2 + " ");            Log.i(TAG, "obj3 = " + obj3 + " \n");            ByteArrayOutputStream buf = new ByteArrayOutputStream();            ObjectOutputStream out = new ObjectOutputStream(buf);            out.writeObject(obj1);            out.writeObject(obj2);            out.writeObject(obj3);            ByteArrayInputStream bufin = new ByteArrayInputStream(buf.toByteArray());            ObjectInputStream in = new ObjectInputStream(bufin);            obj4 = (MyObject) in.readObject();            obj5 = (MyObject) in.readObject();            obj6 = (MyObject) in.readObject();            Log.i(TAG, "读取的对象\n");            Log.i(TAG, "obj4 = " + obj4 + " ");            Log.i(TAG, "obj5 = " + obj5 + " ");            Log.i(TAG, "obj6 = " + obj6 + " ");        } catch (IOException | ClassNotFoundException e) {            e.printStackTrace();        }

代码中obj1,和obj2 同时指向同一个引用,写入buffer,再读从buffer取出来,打印的log如下:


01-04 18:21:58.302 18984-18984/? I/ObjectNet: 写入的对象01-04 18:21:58.302 18984-18984/? I/ObjectNet: obj1 = ( n:1 name:dog useless:here 地址:com.xue.qin.demo.myserialization.MyObject@e3956d8 ) 01-04 18:21:58.302 18984-18984/? I/ObjectNet: obj2 = ( n:1 name:dog useless:here 地址:com.xue.qin.demo.myserialization.MyObject@e3956d8 ) 01-04 18:21:58.303 18984-18984/? I/ObjectNet: obj3 = ( n:2 name:cat useless:there 地址:com.xue.qin.demo.myserialization.MyObject@9effa31 ) 01-04 18:21:58.310 18984-18984/? I/ObjectNet: 读取的对象01-04 18:21:58.310 18984-18984/? I/ObjectNet: obj4 = ( n:1 name:dog useless:null 地址:com.xue.qin.demo.myserialization.MyObject@b4abe69 ) 01-04 18:21:58.311 18984-18984/? I/ObjectNet: obj5 = ( n:1 name:dog useless:null 地址:com.xue.qin.demo.myserialization.MyObject@b4abe69 ) 01-04 18:21:58.311 18984-18984/? I/ObjectNet: obj6 = ( n:2 name:cat useless:null 地址:com.xue.qin.demo.myserialization.MyObject@30d40ee ) 


可以看到,写入时候地址完全一致,符合我们一贯的想法,没啥说的。读取回来的obj4和obj5地址也是一致的,也就是说obj4和obj5是指向同一个引用的。

可见序列化的时候是将引用的关系也写入了,并不是简单的根据引用复制一个对象,而是还复制了对象的指向关系。

另外作为transient 标记的变量useless没有被序列化。

(二)Parcelable

android为了进程间的通信能够高效率的传送信息,使用parcel,必须要接入这个接口parcelable。代码例子如下,使用中可以接入此接口。

package com.xue.qin.demo.myparcelableclass;import android.os.Parcel;import android.os.Parcelable;/** * Created by xue.qin on 2017/6/5. */public class MyObject implements Parcelable {    private int n;    private String name;    private String useless;    public MyObject(){        n=0;        name="default";        useless="default";    }    public MyObject(int n, String name, String useless) {        this.n = n;        this.name = name;        this.useless = useless;    }    public MyObject(Parcel source) {        readFromParcel(source);    }    @Override    public int describeContents() {        return 0;    }    @Override    public void writeToParcel(Parcel dest, int flags) {        dest.writeInt(n);        dest.writeString(name);        dest.writeString(useless);    }    public void readFromParcel(Parcel source) {        this.n = source.readInt();        this.name = source.readString();        this.useless = source.readString();    }    public static final Parcelable.Creator<MyObject> CREATOR = new Creator<MyObject>() {        @Override        public MyObject createFromParcel(Parcel source) {            MyObject myObject2 = new MyObject(source);            return myObject2;        }        @Override        public MyObject[] newArray(int size) {            return new MyObject[size];        }    };    @Override    public String toString() {        return "( n:" + n + " name:" + name + " useless:" + useless + " 地址:" + super.toString() + " )";    }}

关键点1、必须有无参数构造函数。(参数定向tag为  out , inout ,会调用

关键点2、必须按照规范写     writeToParcel和readFromParcel(为什么Parcelable接口中没有这个方法??),(参数定向tag为  out , inout ,会调用))

关键点3、必须按照规范写  public static final Parcelable.Creator<MyObject> CREATOR = new Creator<MyObject>()


接口提供了可供外部调用的静态对象,提供从parcel读取初始化类实例的渠道。,


问题:为什么非得声明为CREATE这个变量名?

是因为例如在AIDL自动生成的代码中就会使用者个变量来创建parcelable的类实例。(相信系统中还要有类似的调用与写法,例如系统中的MotionEvent类就是这样写的)

com.xue.qin.demo.myparcelableclass.MyObject.CREATOR.createFromParcel(data);


这是android约定的写法,CREATOR这样写,在系统中可以畅通无阻,当然也可以自己定义变量名,前提是把自己的AIDL生成文件对应的读取位置也修改了,然后当做java类来使用。

既然安卓提供了这样简洁的写法与规定,最好写成CREATOR。



原创粉丝点击