解锁Android高效数据传输的秘钥 - Parcelable剖析
作为Android开发者,我们经常需要在不同的组件(Activity、Service等)之间传输数据。这里的"传输"往往不仅仅是简单的数据复制,还可能涉及跨进程的内存复制操作。当传输的数据量较大时,这种操作可能会带来严重的性能问题。而Android系统为我们提供了Parcelable这一高效的序列化传输机制,很好地解决了这一痛点。今天,就让我们一起来探讪Parcelable的神奇之处。
一、Parcelable架构与原理
Parcelable是Android中一种高效的序列化机制,用于实现进程间通信(IPC)中的对象传递。
Parcelable相对于Serializable的使用相对复杂一些,但Parcelable的效率相对Serializable也高很多,这一直是Google工程师引以为傲的,Parcelable和Serializable的效率对比Parcelable vs Serializable号称快10倍的效率。
与Serializable接口不同,Parcelable采用的是手工编码的方式,序列化后的数据更为紧凑。系统将数据打包到一个全局内存区域中,可供不同线程/进程共享访问。
1、Parcelable的设计理念
Parcelable的设计理念是在保证一定性能的前提下,尽可能节省内存和CPU开销。
从架构上来看,Parcelable涉及到了Binder驱动、Parcel容器和IPCThreadState等几个关键组件,共同构成了高效的序列化通道:
(1)、Binder驱动
Binder驱动是Android的核心组件之一,负责进程间的数据传输。它在内核层为每个进程维护了一块受保护的共享内存区域,用于在进程间传递Parcelable对象。
(2)、Parcel容器
Parcel对象是存储序列化数据的临时载体。开发者需要先将对象写入Parcel中,然后由Binder驱动完成Parcel在进程间的拷贝和传递。
(3)、IPCThreadState
IPCThreadState是一个线程私有数据结构,负责在进程间管理请求和应答的Parcel对象数据。每个线程在与其他进程通信时,都会使用自己的IPCThreadState实例。
(4)、Parcelable接口
Parcelable接口定义了将对象写入和从Parcel容器读取的抽象协议,开发者需要手动实现这两个序列化方法。系统会按此协议完成对象的编码/解码操作。
序列化的基本流程如下:
- 当一个进程需要向另一个进程传输数据时,会先初始化一个Parcel容器对象;
- 将要传递的Parcelable对象通过writeToParcel()方法写入Parcel容器;
- Binder驱动从发送方进程拷贝这个Parcel容器到内核共享内存区域;
- 接收方进程从共享内存区读取Parcel数据,并通过Parcelable.Creator反序列化出原始对象;
- 接收进程的目标组件(如Activity)即可使用这个反序列化出的对象数据。
整个过程无需经过Java层的序列化操作,因此效率极高。Parcel容器采用面向流的编码格式存储数据,格式紧凑,内存占用小。
此外,Parcelable的实现细节还包括:
- 支持平台默认Java数据类型的高效编解码;
- 使用标志位压缩编码,节省空间;
- 引入Parcel窗口缓存,加快读写效率;
- 等等一系列优化手段。
从架构和流程上看,Parcelable不仅拥有简单的接口定义,而且在系统层得到了全方位的优化支持,使其在Android世界中成为高效低耗的序列化标准。当然,与之对应的是开发者必须自行编写序列化方法的工作量。但从性能的角度来看,这一点工作量是完全值得的。
二、Parcelable接口的使用
要使用Parcelable,需要自己实现这两个接口方法。
// 定义一个数据类MyData,实现Parcelable接口
public class MyData implements Parcelable {private int id;private String name;private boolean isAdult;// 构造函数public MyData(int id, String name, boolean isAdult) {this.id = id;this.name = name;this.isAdult = isAdult;}// 从Parcel反序列化时使用的特殊构造函数protected MyData(Parcel in) {id = in.readInt();name = in.readString();isAdult = in.readByte() != 0;}// writeToParcel方法,将数据写入Parcel@Overridepublic void writeToParcel(Parcel dest, int flags) {dest.writeInt(id);dest.writeString(name);dest.writeByte((byte) (isAdult ? 1 : 0));}// 生成用于反序列的CREATOR对象public static final Creator<MyData> CREATOR = new Creator<MyData>() {@Overridepublic MyData createFromParcel(Parcel in) {return new MyData(in);}@Overridepublic MyData[] newArray(int size) {return new MyData[size];}};// describeContents是一个内部接口标志@Overridepublic int describeContents() {return 0;}// getter/setter ...
}
接着就可以通过Intent、Binder等方式传输这个Parcelable对象了。系统在底层会自动完成序列化和反序列化的工作。
// 使用示例:传递Parcelable对象
public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 创建MyData对象MyData data = new MyData(1, "Jack", true);// 使用Intent传递MyDataIntent intent = new Intent(this, SecondActivity.class);intent.putExtra("data", data);startActivity(intent);}
}// 接收Parcelable对象
public class SecondActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_second);// 从Intent中取出MyData对象MyData data = getIntent().getParcelableExtra("data");if (data != null) {int id = data.getId();String name = data.getName();boolean isAdult = data.isAdult();// 处理data...}}
}
在这个例子中:
- 我们定义了一个MyData类,实现了Parcelable接口。
- 在MyData类中,我们提供了一个用于Parcel反序列化的特殊构造函数,以及writeToParcel和describeContents方法。
- 同时生成了一个CREATOR对象,用于从Parcel重构MyData实例。
- 在MainActivity中,我们创建了一个MyData对象,并通过Intent将它传递给SecondActivity。
- 在SecondActivity中,我们从Intent中取出了MyData对象,可以使用其中的数据。
通过这个案例,你可以看到使用Parcelable传递一个自定义数据对象是非常简单的。只需要完成几个基本方法的实现,就可以实现对象的高效序列化和反序列化。
与手动实现序列化和Binder传递相比,使用Parcelable的代码更加简洁、安全,并得到了系统级的性能优化。这就是Parcelable作为Android高效IPC解决方案的魅力所在。
三、Parcelable的使用场景
以下是Parcelable主要用于的数据传输场景,以及结合案例代码演示和使用Parcelable的优点分析。
1、Activity间传递数据
当从一个Activity导航到另一个Activity时,可以使用Intent携带数据。如果数据对象实现了Parcelable接口,可以直接在Intent中使用。
// 创建Parcelable对象
MyData myData = new MyData("Hello", 123);// 通过Intent传递数据
Intent intent = new Intent(CurrentActivity.this, NextActivity.class);
intent.putExtra("MY_DATA_KEY", myData);
startActivity(intent);
在接收的Activity中:
// 接收Parcelable数据
Intent intent = getIntent();
MyData myData = intent.getParcelableExtra("MY_DATA_KEY");
2、Activity与Service传递数据
Parcelable也可以用于Activity和Service之间的数据传输。可以通过Intent发送数据到Service,或者Service返回结果给Activity。
// Activity发送数据到Service
Intent serviceIntent = new Intent(this, MyService.class);
serviceIntent.putExtra("MY_DATA_KEY", myData);
startService(serviceIntent);
3、通过Binder传输数据
在使用AIDL(Android Interface Definition Language)定义服务时,Parcelable可以用来在客户端和服务器之间传递数据。
// 在AIDL接口定义中
parcelable MyData;
4、将对象保存在Bundle或保存实例状态
在Activity的生命周期中,可以在onSaveInstanceState方法中使用Bundle保存Parcelable对象。
@Override
public void onSaveInstanceState(Bundle outState) {super.onSaveInstanceState(outState);outState.putParcelable("MY_DATA_KEY", myData);
}@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {super.onRestoreInstanceState(savedInstanceState);myData = savedInstanceState.getParcelable("MY_DATA_KEY");
}
四、Parcelable与Serializable的比较
与Java中的Serializable相比,Parcelable有以下优势:
1、性能更优
Parcelable序列化后的码流要比Serializable小得多,内存开销和CPU损耗也更低。
2、使用成本低
Parcelable无需使用反射,只需手写几个方法即可。
3、没有安全隐患
Parcelable不会自动完成数据的深复制,避免了Serializable可能带来的安全隐患。
当然,其缺点是需要手动编码实现序列化逻辑,并维护代码与类结构的同步,工作量较高。而Serializable则可以自动完成序列化。
五、Parcelable的性能优化建议
尽管Parcelable已经相当高效,但我们在实际使用时仍可以通过一些优化手段达到更佳的性能表现:
1、尽量使用标量类型
标量类型(int/long)可以直接通过writeInt/writeLong方法进行序列化,性能较高。
2、减少自动装箱操作
避免对装箱对象进行序列化,如Integer等。应直接使用基本类型。
3、编写高效的Parcelable方法
在writeToParcel方法中应先写入有效数据,而不是创建临时对象。
4、启用Parcelable代码生成器
Parceler等工具可以自动生成Parcelable代码,提高开发效率。
六、不得不提及的Bundler
Parcelable的强大远不止于上述简单用法。在Android 10开始,Google引入了Bundler框架,可以将任意的应用程序数据自动打包成一个Parcelable的Bundle,从而实现高效的跨进程通信。Bundler极大地简化了使用Parcelable的难度。
这一强大功能曾广受期待。令人惋惜的是,Bundler目前的可用性和成熟度似乎还有待提高。但不可否认,Google为我们展现了Parcelable在未来更大的应用前景。
无论是Android系统的Binder,还是Chrome浏览器的IPC数据传输,Parcelable都扮演着举足轻重的角色。它使得Android应用能够高效、安全地在进程间传输数据。面向未来,或许Parcelable的序列化能力会不断增强,甚至取代JVM的Serializable成为跨平台的数据序列化标准。让我们拭目以待吧!
相关文章:
解锁Android高效数据传输的秘钥 - Parcelable剖析
作为Android开发者,我们经常需要在不同的组件(Activity、Service等)之间传输数据。这里的"传输"往往不仅仅是简单的数据复制,还可能涉及跨进程的内存复制操作。当传输的数据量较大时,这种操作可能会带来严重的性能问题。而Android系…...
前端 CSS 经典:filter 滤镜
前言:什么叫滤镜呢,就是把元素里的像素点通过一套算法转换成新的像素点,这就叫滤镜。而算法有 drop-shadow、blur、contrast、grayscale、hue-rotate 等。我们可以通过这些算法实现一些常见的 css 样式。 1. drop-shadow 图片阴影 可以用来…...
专业的力量-在成为专家的道路上前进
专业的力量-在成为专家的道路上前进 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 现在稀缺的已不再是信息资源,而是运用信息的能力。过去…...
10分钟掌握FL Studio21中文版,音乐制作更高效!
FL Studio 21中文版是Image Line公司推出的一款深受欢迎的数字音频工作站软件,在音乐制作领域享有盛誉。这个版本特别针对中文用户进行了本地化处理,旨在提供更加便捷的用户体验和操作界面。本次评测将深入探讨FL Studio 21中文版的功能特点、使用体验及…...
Python中4种读取JSON文件和提取JSON文件内容的方法
在Python中,有几种常用的方法可以用于读取JSON文件并提取数据。以下是四种主要的方法 使用iamn 1oad:0”:这个方法用于格一个包合S0N文档的字符串(enr、wtas典otea实列)反席列化 (0eseia28)为Pm0n%象。例如,如果你有一个ISON格式的字荷电,你…...
el-pagination在删除非第一页的最后一条数据遇到的问题
文章目录 前言一、问题展示二、解决方案三、源码解析1、elementui2、elementplus 总结 前言 这个问题是element-ui中的问题,可以从源码中看出来,虽然页码更新了,active也是对的,但是未调用current-change的方法,这里就…...
视频汇聚平台LntonCVS视频监控系统前端错误日志记录及Debug模式详细讲解
LntonCVS作为一种支持GB28181标准的流媒体服务平台,旨在提供一个能够整合不同厂商设备、便于管理和扩展的解决方案,以适应日益复杂的视频监控环境。通过实现设备的统一管理和流媒体的高效传输,LntonCVS帮助构建更加灵活和强大的视频监控系统。…...
高并发项目-用户登录基本功能
文章目录 1.数据库表设计1.IDEA连接数据库2.修改application.yml中数据库的名称为seckill3.IDEA创建数据库seckill4.创建数据表 seckill_user5.密码加密分析1.传统方式(不安全)2.改进方式(两次加密加盐) 2.密码加密功能实现1.pom.…...
kotlin基础之泛型和委托
Kotlin泛型的概念及使用 泛型概念 在Kotlin中,泛型(Generics)是一种允许在类、接口和方法中使用类型参数的技术。这些类型参数在实例化类、实现接口或调用方法时会被具体的类型所替代。泛型的主要目的是提高代码的复用性、类型安全性和可读…...
awtk踩坑记录二:移植jerryscript到awtk design项目
工作要求,想尝试看看在awtk-designer设计界面的同时能不能用javascript开发逻辑层,以此和前端技术联动,本文是一种项目建构的思路。 从github下载并编译awtk, awtk-mmvm和awtk-jerryscript(如果没有) 用awtk-designer…...
正邦科技(day2)
自动校准 问题:电量不准都可以直接去校准 校准方式:可程式变频电压 问题分析:他是通过软件去自动自动校准的,flash 清空的时候有缓存没有清空,或者互感器没有读取到问题 互感器:电流互感器的作用包括电流测…...
技术架构设计指南:从需求到实现
技术架构是软件系统的骨架,它决定了系统的性能、可靠性、扩展性等关键特性。本文将介绍技术架构设计的一般步骤和方法。 第一步:需求分析 在设计技术架构之前,首先要对系统需求进行全面深入的分析。这包括功能需求、非功能需求(如…...
【数据结构:排序算法】堆排序(图文详解)
🎁个人主页:我们的五年 🔍系列专栏:数据结构课程学习 🎉欢迎大家点赞👍评论📝收藏⭐文章 目录 🍩1.大堆和小堆 🍩2.向上调整算法建堆和向下调整算法建堆:…...
git 派生仓库怎么同步主仓库的新分支
一、git 派生仓库怎么同步主仓库的新分支 要使你的Git派生仓库同步主仓库的新分支,请遵循以下步骤: 1、添加上游仓库(如果尚未添加): 如之前所述,确保上游仓库已经被添加到你的本地仓库。如果没有,使用命…...
对比方案:5款知识中台工具的优缺点详解
知识中台工具为企业和组织高效地组织、存储和分享知识,还能提升团队协作的效率。在选择搭建知识中台的工具时,了解工具的优缺点,有助于企业做出最佳决策。本文LookLook同学将对五款搭建知识中台的工具进行优缺点的简单介绍,帮助企…...
第16章-超声波跟随功能 基于STM32的三路超声波自动跟随小车 毕业设计 课程设计
第16章-超声波跟随功能 无PID跟随功能 //超声波跟随if(HC_SR04_Read() > 25){motorForward();//前进HAL_Delay(100);}if(HC_SR04_Read() < 20){motorBackward();//后退HAL_Delay(100);}PID跟随功能 在pid.c中定义一组PID参数 tPid pidFollow; //定距离跟随PIDpidFol…...
创新案例 | 持续增长,好孩子集团的全球化品牌矩阵战略与客户中心设计哲学
探索好孩子集团如何通过创新设计的全球化品牌矩阵和以客户为中心的产品策略,在竞争激烈的母婴市场中实现持续增长。深入了解其品牌价值观、市场定位策略以及如何满足新一代父母的需求。本文旨在为中高级职场人士、创业家及创新精英提供深度见解,帮助他们…...
ResNet 原理剖析以及代码复现
原理 ResNet 解决了什么问题? 一言以蔽之:解决了深度的神经网络难以训练的问题。 具体的说,理论上神经网络的深度越深,其训练效果应该越好,但实际上并非如此,层数越深会导致越差的结果并且容易产生梯度爆炸…...
数据结构(十)图
文章目录 图的简介图的定义图的结构图的分类无向图有向图带权图(Wighted Graph) 图的存储邻接矩阵(Adjacency Matrix)邻接表代码实现 图的遍历深度优先搜索(DFS,Depth Fisrt Search)遍历抖索过程…...
四数之和-力扣
本题在三数之和的基础上,再增加一重循环进行解答 首先注意的点是,一级剪枝处理,target > 0 && nums[i] > target 此处只有整数才可剪枝处理,如果target为负数,nums[i] < target,也不能代…...
深度解析:Live2D Widget WebSocket实时交互架构实践
深度解析:Live2D Widget WebSocket实时交互架构实践 【免费下载链接】live2d-widget 把萌萌哒的看板娘抱回家 (ノ≧∇≦)ノ | Live2D widget for web platform 项目地址: https://gitcode.com/gh_mirrors/li/live2d-widget 在当今Web应用追求沉浸式体验的浪潮…...
周红伟:OpenClaw 企业级智能体架构与全栈实战
周红伟“世界级 OpenClaw 智能体全栈实战培训方案”。 这套方案融合了架构设计、全链路开发、安全部署与商业落地四大维度,旨在帮助企业团队从“理论认知”跨越到“工程化落地”,构建具备生产级能力的AI智能体系统。 🚀 培训主题:…...
从拖拽到对话:衡石Agentic BI如何重构企业数据分析的交互范式
传统BI的交互困局在商业智能发展史上,2025年或许会被标记为一个转折点。这一年,衡石科技发布的HENGSHI SENSE 6.0 Agentic BI平台,标志着数据分析从"被动工具"正式迈入"主动智能体"时代。过去二十年,"拖拽生成报表"一直被奉为BI工具的黄金标准。…...
OpenClaw技能系统深度指南:打造能干活、守规矩、够聪明的工具化 AI 助手
手把手教你一键部署OpenClaw,连接微信、QQ、飞书、钉钉等,1分钟全搞定! AI 智能体想从只会动嘴皮子的“聊天机器人”变成真正能干活的“行动派”,能不能熟练使用工具就是一道分水岭。OpenClaw 的 Skills 系统,说白了就…...
Wan2.2-I2V-A14B效果展示:RTX4090D优化版生成高清视频作品集,开箱即用
Wan2.2-I2V-A14B效果展示:RTX4090D优化版生成高清视频作品集,开箱即用 1. 惊艳效果预览:专业级视频生成能力 当第一次看到Wan2.2-I2V-A14B生成的视频作品时,很难相信这些画面完全由AI从文字描述创造。这款专为RTX4090D优化的文生…...
Mac用户必看:Homebrew换源提速全攻略(附清华镜像最新配置)
Mac开发者必备:Homebrew国内镜像加速终极指南 每次打开终端准备用Homebrew安装新工具时,那个缓慢的下载进度条是否让你抓狂?作为Mac生态中最受欢迎的包管理工具,Homebrew的默认服务器位于海外,国内用户常遭遇下载速度以…...
ESP32 BLE MTU 协商实战:从原理到手机端配置优化
1. 理解BLE MTU协商的核心概念 第一次接触BLE开发时,我也被MTU这个概念搞得一头雾水。简单来说,MTU(Maximum Transmission Unit)就像快递包裹的尺寸限制 - 它决定了每次传输能携带多少数据。在BLE通信中,默认的MTU只有…...
【AI黑话日日新】什么是大语言模型驱动的代码生成技术?
摘要 生成式人工智能的快速普及,重塑了传统软件开发的全链路流程。大语言模型(LLM)凭借海量语料预训练与深度语义理解能力,成为智能代码生成的核心底座。这项技术打通了自然语言与编程语言的语义壁垒,能够实现代码续写、需求转源码、自动化测试、系统重构等多元化能力,帮…...
机器人状态估计——从IMU运动方程到ESKF误差状态建模(上)
1. 从IMU数据到机器人状态估计的挑战 当你第一次拿到一个IMU传感器时,可能会觉得它就像个魔法黑盒——只要把它装在机器人上,就能知道机器人的姿态、速度和位置。但实际操作起来,你会发现IMU数据就像个调皮的孩子,稍不注意就会给你…...
SmolVLA详细步骤:从start.sh启动到app.py调试的完整开发流程
SmolVLA详细步骤:从start.sh启动到app.py调试的完整开发流程 1. 项目概述与环境准备 SmolVLA是一个专为经济实惠的机器人技术设计的紧凑高效视觉-语言-动作模型。这个模型将视觉感知、语言理解和动作生成融合在一个轻量级架构中,让开发者能够快速构建智…...
