android 序列化传参数,Android序列化之Parcelable和Serializable的使用详解
序列化与反序列
首先来了解一下序列化与反序列化。
序列化
由于存在于内存中的对象都是暂时的,无法长期驻存,为了把对象的状态保持下来,这时需要把对象写入到磁盘或者其他介质中,这个过程就叫做序列化。
反序列化
反序列化恰恰是序列化的反向操作,也就是说,把已存在在磁盘或者其他介质中的对象,反序列化(读取)到内存中,以便后续操作,而这个过程就叫做反序列化。
概括性来说序列化是指将对象实例的状态存储到存储媒体(磁盘或者其他介质)的过程。在此过程中,先将对象的公共字段和私有字段以及类的名称(包括类所在的程序集)转换为字节流,然后再把字节流写入数据流。在随后对对象进行反序列化时,将创建出与原对象完全相同的副本。
实现序列化的必要条件
一个对象要实现序列化操作,该类就必须实现了Serializable接口或者Parcelable接口,其中Serializable接口是在java中的序列化抽象类,而Parcelable接口则是android中特有的序列化接口,在某些情况下,Parcelable接口实现的序列化更为高效,关于它们的实现案例我们后续会分析,这里只要清楚知道实现序列化操作时必须实现Serializable接口或者Parcelable接口之一即可。
序列化的应用情景
主要有以下情况(但不限于以下情况)
1)内存中的对象写入到硬盘;
2)用套接字在网络上传送对象;
3)通过RMI(Remote Method Invoke 远程方法调用)传输对象;
1.Parcelable和Serializable有什么用,它们有什么差别?
Parcelable和Serializable是两个接口,它们的作用是让实现了其中一个接口的类的对象能够被序列化和反序列化。
(1)Serializable是java提供的序列化接口,它是一个空的接口,仅标识该类型可序列化的,具体的序列化/反序列化工作由 ObjectInputStream(readObject)/ObjectOutputStream(writeObject) 完成,这个过程包含大量的I/O操作,使用比较简单,但需要考量性能的影响。使用场景:将对象持久化到存储介质或者通过网络传输。
(2)Parcelable接口是Android平台下的序列化接口,通常跨进程传递的数据都要正确实现这个接口,比如Intent,Bitmap等。Parcelable实现起来比Serializable复杂,但性能较好。使用场景:在内存中实现序列化,例如跨进程传递。若某个字段不需要序列化,在实现 writeToParcel 方法中忽略此字段即可。
2.自定义一个类让其实现Parcelable,大致流程是什么?
(1)首先实现Parcelable接口,并实现接口中的方法。
/**
* 返回当前对象的内容描述,如果有文件描述符返回1,否则返回0。
*/
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(userId);
dest.writeString(userName);
dest.writeInt(isMan ? 1 : 0);
}
(2)接着创建一个Parcelable接口内部的接口类型Creator的一个成员,内部需要用到一个带一个Parcel参数的构造方法。
protected User(Parcel in) {
userId = in.readInt();
userName = in.readString();
isMan = in.readByte() != 0;
}
/**
* 在aidl中,参数使用in或者inout来修饰时,服务端的onTransact()会调用CREATOR中方法来反序列化客户端传过来的参数
*/
public static final Creator CREATOR = new Creator() {
@Override
public User createFromParcel(Parcel in) {
return new User(in);
}
@Override
public User[] newArray(int size) {
return new User[size];
}
};
(3)如果在aidl文件中使用out或者inout定向tag来修饰参数,还必须实现一个 readFromParcel(Parcel) 方法,这是因为使用这两个定向tag修饰的参数,在服务端onTransact()返回后,客户端会调用 readFromParcel() 来读取(反序列化)_reply中的数据。该方法与writeToParcel是对应的,实现如下:
public void readFromParcel(Parcel in) {
userId = in.readInt();
userName = in.readString();
isMan = in.readInt() == 1 ? true : false;
}
3.实现Serializable接口
通过实现Serializable接口来实现序列化比较简单,只需要实现该接口,并指定 serialVersionUID 即可,当然这个ID是可选的,可以不手动指定。通过ObjectIntputStream /ObjectOutputStream来序列化和反序列化。
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(new FileOutputStream(new File("sdcard/user.cache")));
User user = new User(111, "Jdqm", true);
oos.writeObject(user);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(new FileInputStream(new File("sdcard/user.cache")));
User user = (User) ois.readObject();
Log.d(TAG, "user: " + user);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
} finally {
try {
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
输出结果
User{userId=111, userName='Jdqm', isMan=true}
serialVersionUID的意义:辅助完成序列化和反序列化,当一个类实现SerSerializable接口,没有添加serialVersionUID的作用字段时,IDE会发出警告,这个字段可以手动指定一个值,比如1L,也可指定为IED根据类的结构生成一个long值,它们的效果是一样的。在序列化时会将这个值写入存储介质,反序列化时就校验本地类的serialVersionUID和序列化介质中的是否一致,不一致将抛出异常 java.io.InvalidClassException
(1)若不指定:系统会根据类的结构计算出一个serialVersionUID,一旦类的结构发生改变这个值就会改变,将导致反序列化失败;
(2)指定一个值:当类的结构发生改变时,也可以不修改serialVersionUID的值,这种情况下能最大程度上通过反序列化回复数据,若类的结构发生毁灭性的改变,例如字段数据类型改变了,也会导致反序列失败。
Note: 类的结构发生改变指的是类的成员变量的改变,添加一个普通的方法是不会导致计算得到的serialVersionUID改变的。构造方法、toString()、getter/setter改变会引起serialVersionUID改变。
transient修饰的成员变量不参与序列化,反序列化时改成员为该数据类型的默认值
静态成员不参与序列化
反序列化得到的一个新对象的过程并没有调用构造方法
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。
android 序列化传参数,Android序列化之Parcelable和Serializable的使用详解相关推荐
- android 序列化传参数,android 传值 序列化
Activity之间传数据时,为了避免麻烦,往往会将一些值封装成对象,然后将整个对象传递过去.传对象的时候有两种情况,一种是实现Parcelable接口,一种是实现Serializable接口. 0. ...
- android registerreceiver传参数,Android应用程序注册广播接收器(registerReceiver)的过程分析...
前面我们介绍了Android系统的广播机制,从本质来说,它是一种消息订阅/发布机制,因此,使用这种消息驱动模型的第一步便是订阅消息:而对Android应用程序来说,订阅消息其实就是注册广播接收器,本文 ...
- Android基础入门教程——8.3.1 三个绘图工具类详解
Android基础入门教程--8.3.1 三个绘图工具类详解 标签(空格分隔): Android基础入门教程 本节引言: 上两小节我们学习了Drawable以及Bitmap,都是加载好图片的,而本节我 ...
- 【Android语音合成TTS】百度语音接入方法,和使用技巧详解
请尊重他人的劳动成果,转载请注明出处:[Android语音合成TTS]百度语音接入方法,和使用技巧详解 Ps. 依托于百度开放云,百度语音为合作伙伴提供了业界领先.永久免费的语音技术服务,目前已上线的 ...
- 【Android游戏开发十二】(保存游戏数据 [上文])详解SharedPreference 与 FIleInputStream/FileOutputStream将数据存储到SD卡中!
李华明Himi 原创,转载务必在明显处注明: 转载自 [黑米GameDev街区] 原文链接: http://www.himigame.com/android-game/327.html 很多童鞋说 ...
- android 6.0 存储卡,Android 6.0区别U盘和SD卡设备的方法详解
如下所示: public static boolean isSdcardExists(Context context) { StorageManager storageManager = Storag ...
- android调用webservice传参数,android调用webservice接口获取信息
我的有一篇博客上讲了如何基于CXF搭建webservice,service层的接口会被部署到tomcat上,这一篇我就讲一下如何在安卓中调用这些接口传递参数. 1.在lib中放入ksoap2的jar包 ...
- Android群英传笔记-Android系统安全与安全机制
Android系统安全与安全机制 系统消息 Android系统消息获取 android.os.Build SystemProperty Android apk 应用信息获取 PackageManage ...
- android 群英传笔记,Android 群英传读书笔记1
Android中每个控件都会在界面上占据一块矩形的区域,在Android中控件被分为两种,①VIew ②ViewGroup ViewGroup可以包含多个View 或者Viewgroup 这样在界面 ...
最新文章
- 决策树--信息增益,信息增益比,Geni指数的理解
- 解决.Net Core跨域问题
- ​Highmaps网页图表教程之绘图区显示标签显示数据标签定位
- UA MATH571A 回归分析 概念与R code总结
- linux每日命令(14):less命令
- 基础知识:IDE集成开发环境(pycharm)、基本数据类型、用户的交互、运算符
- ZooKeeper安装配置
- php显示服务器拒绝连接失败,php – SMTP ERROR:无法连接到服务器:连接被Office365拒绝(111)...
- ES6 解构赋值的用法笔记
- gitlab 删除分支_如何删除gitlab上默认受保护的master主分支
- 爬虫03-url的格式
- Eclipse InstaSearch搜索词法 (很多并不支持)
- 236 Lowest Common Ancestor of a Binary Tree
- synchronized 详解,偏向锁,轻量锁,重量锁
- android标签切换卡,Android切换卡TabWidget用法示例
- Flash Builder4.6 入门Demo_trace
- 微信翻译团队课余也搞围棋AI:比腾讯绝艺更强,首次亮相就夺冠
- 莫烦python讲得好差_莫烦PYTHON——PyTorch——DQN 代码详解
- 微信小程序弹框种类汇总
- 个人微信小程序开发入门教程:注册个人小程序
热门文章
- svn 把本地的项目,上传到服务器端
- EasyUI DataGrid undefined处理
- [转摘] 我的同学聚会--性格决定命运
- Jupyter 中 ValueError: Duplicate names are not allowed.的问题解决
- 阿里巴巴Java开发手册v1.2.0版
- Android Audio打开输出设备流程(十五)
- Android视频录制-MediaRecorder流程
- Linux/Android的cpu/memory/磁盘占用情况
- pandas.read_csv() 详解与如何合适的读取行序号与列名
- 用户、话题、评论一网打尽,分享一个最强微博爬虫