Android中序列化

(一)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 CREATOR = new Creator() {
        @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 CREATOR = new Creator()


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


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

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

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


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

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



你可能感兴趣的:(andorid,基础)