找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

1376

积分

0

好友

233

主题
发表于 2025-12-27 10:33:09 | 查看: 30| 回复: 0

本文详细介绍了 Android 开发中两种关键的对象序列化方式:SerializableParcelable。序列化是实现跨进程通信(IPC)和数据持久化的基础,理解两者的区别与适用场景,对于提升应用性能至关重要。Serializable 是 Java 标准库提供的通用方案,而 Parcelable 则是 Android 平台专为高性能 IPC 设计。本文将深入解析其使用方法、性能差异以及选择策略。

一、序列化基础概念

在 Android 中,当我们需要通过 IntentBinder 传输复杂对象,或者需要将对象持久化到存储设备、通过网络传输时,就必须将对象转换为可以存储或传输的格式,这个过程称为序列化。其逆过程,即从序列化后的数据重建对象,称为反序列化。

简单理解,序列化就像为了运输而将房子拆解成标准化的零部件;反序列化则是到达目的地后,根据图纸重新组装房子。这两个接口正是完成“拆解”与“组装”的蓝图。

二、Serializable 接口详解

Serializable 是 Java 标准库提供的一个标记接口(一个空接口),用于声明一个类可以被序列化。

如何实现序列化?

要让一个类支持序列化非常简单,只需声明实现 Serializable 接口,并定义一个名为 serialVersionUID 的静态长整型常量即可。

import java.io.Serializable;

public class User implements Serializable {
    // 序列化版本号,用于验证反序列化时类的版本一致性
    private static final long serialVersionUID = 51906712373232662L;

    public int userId;
    public String userName;
    public boolean isMale;

    // 构造方法
    public User(int userId, String userName, boolean isMale) {
        this.userId = userId;
        this.userName = userName;
        this.isMale = isMale;
    }
}

序列化与反序列化操作

完成类定义后,可以使用 ObjectOutputStreamObjectInputStream 轻松实现对象的序列化(写入)与反序列化(读取)。

// 序列化过程:将对象写入文件
User user = new User(0, "Jack", true);
try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("user.txt"))) {
    out.writeObject(user);
} catch (IOException e) {
    e.printStackTrace();
}

// 反序列化过程:从文件读取对象
User newUser;
try (ObjectInputStream in = new ObjectInputStream(new FileInputStream("user.txt"))) {
    newUser = (User) in.readObject();
} catch (IOException | ClassNotFoundException e) {
    e.printStackTrace();
}

理解 serialVersionUID 的重要性

serialVersionUID 是序列化机制的“版本号”。其工作机制如下:

  • 序列化时:系统将当前类的 serialVersionUID 写入序列化数据。
  • 反序列化时:系统会检查数据中的 serialVersionUID 是否与当前类的 serialVersionUID 一致。
  • 如果一致,说明类的版本相同,反序列化成功。
  • 如果不一致,意味着序列化后的类可能已被修改(如增删字段),反序列化会失败并抛出 InvalidClassException

如果不显式声明 serialVersionUID,Java 虚拟机会根据类结构自动生成一个。一旦类发生任何改变,这个自动生成的值就会变化,导致已序列化的旧数据无法被新版本的类读取。因此,显式声明一个固定的 serialVersionUID 是保证序列化兼容性的最佳实践

注意事项

  • 静态成员变量属于类而非对象,不参与序列化。
  • 使用 transient 关键字修饰的成员变量,也会被排除在序列化过程之外。

Java 平台的序列化方案虽然通用,但其涉及大量 I/O 操作和反射,在资源受限的 Android 移动平台上开销较大。

三、Parcelable 接口详解

Parcelable 是 Android SDK 专为高性能 IPC 设计的序列化接口。它直接操作内存,避免了 Serializable 的反射和 I/O 开销,效率极高,是 Android 官方推荐的序列化方式。

如何实现 Parcelable?

在 Android Studio 中,实现 Parcelable 接口后,IDE 可以自动生成大部分模板代码,大大简化了开发过程。

  1. 首先,让类实现 Parcelable 接口。

    在Android Studio中实现Parcelable接口

  2. 将光标移至类名上,按 Alt + Enter,选择 “Add Parcelable implementation”,IDE 会自动生成必要的序列化代码。

    IDE自动生成Parcelable实现代码

  3. 以下是自动生成并稍作整理后的完整 Parcelable 实现代码:

import android.os.Parcel;
import android.os.Parcelable;

public class User implements Parcelable {
    public int userId;
    public String userName;
    public boolean isMale;

    // 构造方法
    public User(int userId, String userName, boolean isMale) {
        this.userId = userId;
        this.userName = userName;
        this.isMale = isMale;
    }

    // 从 Parcel 中反序列化对象的构造方法
    protected User(Parcel in) {
        userId = in.readInt();
        userName = in.readString();
        isMale = in.readByte() != 0;
    }

    // 负责反序列化的 CREATOR
    public static final Creator<User> CREATOR = new Creator<User>() {
        @Override
        public User createFromParcel(Parcel in) {
            return new User(in);
        }

        @Override
        public User[] newArray(int size) {
            return new User[size];
        }
    };

    // 内容描述(通常返回0,若包含文件描述符则返回1)
    @Override
    public int describeContents() {
        return 0;
    }

    // 序列化:将对象数据写入 Parcel
    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(userId);
        dest.writeString(userName);
        dest.writeByte((byte) (isMale ? 1 : 0));
    }
}

Parcelable 核心方法说明

方法 功能 常见标记位
writeToParcel(Parcel dest, int flags) 将当前对象的数据写入 Parcel PARCELABLE_WRITE_RETURN_VALUE (几乎总为0)
describeContents() 返回对象内容的特殊描述。若无文件描述符,返回0。 CONTENTS_FILE_DESCRIPTOR (仅当包含文件描述符时返回1)
Creator.createFromParcel(Parcel in) Parcel 中读取数据,构造一个新的对象。 -
Creator.newArray(int size) 创建指定大小的对象数组。 -
User(Parcel in) (构造方法) createFromParcel 配合,完成对象的创建与初始化。 -

四、Serializable 与 Parcelable 如何选择?

了解了两种接口的实现和原理后,如何在项目中做出选择?

  1. 开发效率与平台通用性

    • Serializable:使用极其简单,只需声明一个接口和一个ID。它是 Java 平台标准,适合需要将对象序列化到存储设备(如文件)或通过网络传输(如RPC)到其他Java服务的场景。
    • Parcelable:实现相对繁琐,但Android Studio的自动生成功能大大降低了难度。它是Android特有API,专为进程内和跨进程(AIDL)内存数据传输优化。
  2. 性能

    • Serializable:序列化和反序列化过程开销较大,涉及大量I/O、反射和临时对象的创建,会产生可观的垃圾回收(GC)压力。
    • Parcelable性能极高。它直接在内存中进行读写操作,避免了反射和多余的I/O,是Android系统组件间(如Activity/Fragment/Services)传递数据时的首选。
  3. 适用场景总结

    • 首选 Parcelable:在 Android 平台内进行对象传输,尤其是通过 Intent 在组件间传递、或通过 Binder 进行跨进程通信(AIDL)时,必须使用 Parcelable 以获得最佳性能。
    • 使用 Serializable:当需要将对象持久化到本地文件,或序列化后通过网络传输到非Android的Java后端服务时,Serializable 是更通用、更合适的选择。虽然也可以使用 Parcelable 完成持久化,但过程会更复杂。

核心结论:对于 Android 应用开发,在内存间传递数据优先使用高效的 Parcelable;在需要将数据写入 数据库 或文件进行长期存储,或与Java后端交互时,则可使用 Serializable




上一篇:使用TensorFlow 2.x实现GoogLeNet进行Fashion-MNIST服饰图像分类实战
下一篇:TensorFlow实战:ResNet50与ResNet18在Fashion-MNIST和CIFAR10图像分类任务中的应用
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-1-12 03:02 , Processed in 0.284631 second(s), 39 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2025 云栈社区.

快速回复 返回顶部 返回列表