Android -- Serializable和Parcelable需要注意的

简介:

Serializable

  • 静态变量序列化不会被保存
复制代码
public class Test implements Serializable {

    private static final long serialVersionUID = 1L;

    public static int staticVar = 5;

    public static void main(String[] args) {
        try {
            //初始时staticVar为5
            ObjectOutputStream out = new ObjectOutputStream(
                    new FileOutputStream("result.obj"));
            out.writeObject(new Test());
            out.close();

            //序列化后修改为10
            Test.staticVar = 10;

            ObjectInputStream oin = new ObjectInputStream(new FileInputStream(
                    "result.obj"));
            Test t = (Test) oin.readObject();
            oin.close();
            
            //再读取,通过t.staticVar打印新的值
            System.out.println(t.staticVar);
            
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}
复制代码

最后的输出是 10

  • 父类的序列化与 Transient 关键字

一个子类实现了 Serializable 接口,它的父类都没有实现 Serializable 接口,序列化该子类对象,然后反序列化后输出父类定义的某变量的数值,该变量数值与序列化时的数值不同。

要想将父类对象也序列化,就需要让父类也实现Serializable 接口。如果父类不实现的话的,就 需要有默认的无参的构造函数。如果你考虑到这种序列化的情况,在父类无参构造函数中对变量进行初始化,否则的话,父类变量值都是默认声明的值,如 int 型的默认是 0,string 型的默认是 null。

我们熟悉使用 Transient 关键字可以使得字段不被序列化,那么还有别的方法吗?根据父类对象序列化的规则,我们可以将不需要被序列化的字段抽取出来放到父类中,子类实现 Serializable 接口,父类不实现,根据父类序列化规则,父类的字段数据将不被序列化。

  • 序列化存储规则
复制代码
ObjectOutputStream out = new ObjectOutputStream(
                    new FileOutputStream("result.obj"));
    Test test = new Test();
    //试图将对象两次写入文件
    out.writeObject(test);
    out.flush();
    System.out.println(new File("result.obj").length());
    out.writeObject(test);
    out.close();
    System.out.println(new File("result.obj").length());

    ObjectInputStream oin = new ObjectInputStream(new FileInputStream(
            "result.obj"));
    //从文件依次读出两个文件
    Test t1 = (Test) oin.readObject();
    Test t2 = (Test) oin.readObject();
    oin.close();
            
    //判断两个引用是否指向同一个对象
    System.out.println(t1 == t2);
复制代码

对同一对象两次写入文件,打印出写入一次对象后的存储大小和写入两次后的存储大小,然后从文件中反序列化出两个对象,比较这两个对象是否为同一对象。一般的思维是,两次写入对象,文件大小会变为两倍的大小,反序列化时,由于从文件读取,生成了两个对象,判断相等时应该是输入 false 才对,但是。。。

1

我们看到,第二次写入对象时文件只增加了 5 字节,并且两个对象是相等的。。Java 序列化机制为了节省磁盘空间,具有特定的存储规则,当写入文件的为同一对象时,并不会再将对象的内容进行存储,而只是再次存储一份引用,上面增加的 5 字节的存储空间就是新增引用和一些控制信息的空间。反序列化时,恢复引用关系,使得代码中的 t1 和 t2 指向唯一的对象,二者相等,输出 true。该存储规则极大的节省了存储空间。

Parcelable

android.os.BadParcelableException: ClassNotFoundException when unmarshalling

复制代码
public Config config;
public RowView(Parcel in){
    type = in.readString();
    interfaceUrl = in.readString();
    size = in.readInt();
    config = in.readParcelable(null);
}
复制代码

报错的语句即为config = in.readParcelable(null);

  • 分析

根据android文档介绍:

readParcelable (ClassLoader loader)

loader A ClassLoader from which to instantiate the Parcelable object, or null for the default class loader.即loader为空时系统会采取默认的class loader。

Android有两种不同的classloaders:framework classloader和apk classloader,其中framework classloader知道怎么加载android classes,apk classloader知道怎么加载you code,apk classloader继承自framework classloader,所以也知道怎么加载android classes。

在应用刚启动时,默认class loader是apk classloader,但在系统内存不足应用被系统回收会再次启动,这个默认class loader会变为framework classloader了,所以对于自己的类会报ClassNotFoundException。

  • 解决

 

将config = in.readParcelable(null);改为config = in.readParcelable(Config.class.getClassLoader());

Config.class.getClassLoader()即为apk classloader, 其中Config.class可以改为你程序中自己写的任意类,因为他们同样指向apk loader。

试着改为config = in.readParcelable(Activity.class.getClassLoader());你会发现依然ClassNotFoundException因为Activity.class.getClassLoader()指向的是framework classloader




本文转自我爱物联网博客园博客,原文链接:http://www.cnblogs.com/yydcdut/p/4470190.html,如需转载请自行联系原作者

相关文章
|
4月前
|
存储 Java 开发工具
[Android]序列化原理Parcelable
[Android]序列化原理Parcelable
47 0
|
4月前
|
存储 Java Android开发
[Android]序列化原理Serializable
[Android]序列化原理Serializable
44 0
|
8月前
|
Java Android开发
Android 中通过Intent传递类对象,通过实现Serializable和Parcelable接口两种方式传递对象
Android 中通过Intent传递类对象,通过实现Serializable和Parcelable接口两种方式传递对象
76 1
|
11月前
|
Android开发
AS插件-Android Parcelable code generator.
AS插件-Android Parcelable code generator.
89 0
|
存储 Java Android开发
Android 序列化(Serializable和Parcelable)
🔥 什么是序列化 由于存在于内存中的对象都是暂时的,无法长期驻存,为了把对象的状态保持下来,这时需要把对象写入到磁盘或者其他介质中,这个过程就叫做序列化。 🔥 为什么序列化 永久的保存对象数据(将对象数据保存在文件当中,或者是磁盘中)。 对象在网络中传递。 对象在IPC间传递。
213 0
Android 序列化(Serializable和Parcelable)
|
Android开发 Java 开发工具
Android Parcelable数据序列化详解
什么是什么是Parcelable Parcelable是Android sdk提供的用实现于数据序列化的一个接口,不同于Java中的基于磁盘或者网络的Serializable,Parcelable是基于内存的,由于内存的读写速度高于磁盘,因此在Android中跨进程对象传递一般使用Parcelable。
1300 0
|
Android开发
Android项目实战(十九):Android Studio 优秀插件: Parcelable Code Generator
原文:Android项目实战(十九):Android Studio 优秀插件: Parcelable Code Generator Android Studio 优秀插件系列:                       Android Studio 优秀插件(一):GsonFormat    ...
913 0
|
Android开发 存储 程序员
Android 面试(七):Serializable 这么牛逼,Parcelable 要你何用?
连载内容镇楼:Android 面试(一 ):说说 Android 的四种启动模式Android 面试(二): 如何理解 Activity 的生命周期Android 面试(三): 用广播 BroadcastReceiver 更新 UI 界面真的好吗?An...
1340 0