Android 中 Serializable 与 Parcelable 的对比与选择

文章目录

    • 一、为什么需要序列化
    • [二、Serializable --- Java 原生方式](#二、Serializable — Java 原生方式)
      • [2.1 基本用法](#2.1 基本用法)
      • [2.2 传递数据](#2.2 传递数据)
      • [2.3 原理简析](#2.3 原理简析)
    • [三、Parcelable --- Android 专属方案](#三、Parcelable — Android 专属方案)
      • [3.1 基本用法](#3.1 基本用法)
      • [3.2 读取和写入顺序必须一致](#3.2 读取和写入顺序必须一致)
      • [3.3 传递数据](#3.3 传递数据)
      • [3.4 原理简析](#3.4 原理简析)
    • 四、性能对比
    • 五、总结

一、为什么需要序列化

Android 中几个典型场景都需要序列化:

  • Intent 传递对象intent.putExtra("user", user)
  • Fragment 传递参数 :通过 Bundle 传对象
  • 进程间通信(IPC):AIDL 跨进程传递数据
  • 状态保存onSaveInstanceState 保存页面状态

以上场景中,数据需要被转换成能在组件间传递的二进制流,这个过程就是序列化


二、Serializable --- Java 原生方式

Serializable 是 Java 标准库自带的接口,使用非常简单,只需在类上实现即可。

2.1 基本用法

java 复制代码
public class User implements Serializable {
    private String name;
    private int age;

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // getter / setter 省略...
}

2.2 传递数据

java 复制代码
// 发送端
User user = new User("张三", 25);
Intent intent = new Intent(this, SecondActivity.class);
intent.putExtra("user", user);
startActivity(intent);

// 接收端
User user = (User) getIntent().getSerializableExtra("user");

2.3 原理简析

Serializable 底层通过 Java 反射机制 进行序列化:

  1. 遍历类的所有字段,通过反射读取值
  2. 将字段名、类型、值写入输出流
  3. 反序列化时通过反射创建对象,再逐个赋值

因为依赖反射,过程中会产生大量临时对象,频繁触发 GC,性能较差。


三、Parcelable --- Android 专属方案

Parcelable 是 Android SDK 提供的接口,专门为 Android 场景优化。

3.1 基本用法

java 复制代码
public class User implements Parcelable {
    private String name;
    private int age;

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // 从 Parcel 中读取数据,构造对象
    protected User(Parcel in) {
        name = in.readString();
        age = in.readInt();
    }

    // 将对象数据写入 Parcel
    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(name);
        dest.writeInt(age);
    }

    // 一般返回 0 即可,特殊场景才用文件描述符
    @Override
    public int describeContents() {
        return 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];
        }
    };

    // getter / setter 省略...
}

3.2 读取和写入顺序必须一致

这是最容易出错的地方:writeToParcel 的写入顺序,必须和构造函数中 readXxx 的读取顺序完全一致

java 复制代码
// 正确:写入顺序和读取顺序一致
dest.writeString(name);      // 写入 ①
dest.writeInt(age);           // 写入 ②

name = in.readString();       // 读取 ①
age = in.readInt();           // 读取 ②
java 复制代码
// 错误:顺序不一致会导致数据错乱
dest.writeString(name);
dest.writeInt(age);

age = in.readInt();           // 先读了 age,但 Parcel 里排第一的是 String
name = in.readString();

3.3 传递数据

用法和 Serializable 一样,接收端换成 getParcelableExtra

java 复制代码
// 发送端
User user = new User("张三", 25);
intent.putExtra("user", user);

// 接收端
User user = getIntent().getParcelableExtra("user");

3.4 原理简析

Parcelable 不依赖反射,而是手动将字段按顺序拆解并写入 Parcel(一块共享内存)

  1. 你手动指定每个字段如何写入内存
  2. 序列化后数据存储在 Parcel 容器中(底层是 Native 内存)
  3. 反序列化时按写入顺序逐一读取,直接赋值

整个过程不走反射,无临时对象开销,是纯手工的高效方案。


四、性能对比

对比维度 Serializable Parcelable
实现复杂度 低,implements 即可 高,需手动写大量模板代码
序列化速度 慢(反射 + 大量临时对象) 快(直接内存读写)
内存占用 高(GC 压力大) 低(共享内存,无额外对象)
跨进程支持 支持(Java 标准) 支持(Android 专属)
持久化存储 支持(可存文件/数据库) 不推荐(版本升级数据不兼容)

一个具体的对比数据

序列化 1000 个包含 3 个字段的简单对象,Parcelable 比 Serializable 快 10 倍以上 ,内存占用仅为后者的 1/3

这也是为什么 Android 官方文档明确推荐:在 Intent / Bundle 传递数据时使用 Parcelable


五、总结

Serializable 胜在简单,Parcelable 胜在高效。

实际开发中,面向 Intent 传参的场景优先用 Parcelable。如果你觉得手写 Parcelable 太繁琐,可以借助 Android Studio 的插件(如 Parcelable 代码生成器)来一键生成。

相关推荐
_阿南_3 小时前
flutter 展示的字体突然奔放了
android·flutter·ios
文人sec6 小时前
MySQL事务与索引做了什么?
android·笔记·mysql
刘洋浪子6 小时前
AndroidStudio保存日志菜单
android
朱涛的自习室6 小时前
从 Prompt 到 Graph:AI 工程的进化史
android·前端·人工智能
157092511349 小时前
ViewBinding与DataBinding区别与选型
android
小乖写代码10 小时前
49款开源Android小游戏
android·游戏
三少爷的鞋11 小时前
小团队的最优解:单 Module + 包内 Clean 架构
android
爱和冰阔落11 小时前
【Linux】两个毫无关系的进程怎么通信?命名管道 FIFO 从原理到 Server/Client 实战
android·linux·数据库·c++·vim
Android-Flutter11 小时前
kotlin 协程 - 核心概念
android·kotlin