目录
一 序列化定义
一种用于传输对象的数据格式.
notes: 普通char类型直接传输即可.
二 序列化作用
读写(传输)对象
1)永久性保存对象,保存对象的字节序列到本地文件中;(文件)
2)通过序列化对象在网络中传递对象;(网络)
3)通过序列化在进程间传递对象。(进程)
三 分类
序列化分成Serializable和Parcelble 两种序列化. 前者是java的方式,后者是android特有.
实现序列化的方式: 二进制,xml,json,protobuffer.
Serializable和Parcelble 区别
- 1、Serializable的本质是使用了反射,序列化的过程比较慢,这种机制在序列化的时候会创建很多临时的对象,比引起频繁的GC、
- 2、Parcelable方式的本质是将一个完整的对象进行分解,而分解后的每一部分都是Intent所支持的类型,这样就实现了传递对象的功能了
四 Serializable使用实例
4.1 文件,进程,网络
1) 文件读写序列化
//序列化过程
Book book = new Book(123,"Android 开发艺术探索");
FileOuputStream fos = new FileOutputStream("test.txt");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(book);
oss.close();
//反序列化过程
FileInputStream fis = new FileInputStream("test.txt");
ObjectInputStream ois = new ObjectInputStream(fis);
Book newBook = (Book)ois.readObject();
ois.close();
- 网络
in = new java.io.ObjectInputStream(socket.getInputStream());
Java Serializable序列化Socket传送例子 http://blog.chinaunix.net/uid-14767524-id-3399136.html
- 进程
//MainActivity.java
Book book = new Book(123, "android开发艺术探索");
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
intent.putExtra("book",book);
startActivity(intent);
//SecondActivity.java
Intent intent = getIntent();
Book book = intent.getSerializableExtra("book");
**4.2 二进制序列化,xml,json,protobuf
- 二进制序列化**
定义对象(要传输的对象)
public static class Person implements Serializable {
private static final long serialVersionUID = 233858934995755239L;
private String firstName;
private String lastName;
......
}
二进制序列化对象.
//创建一个ObjectOutputStream输出流
outStream = new ObjectOutputStream(new FileOutputStream(filePath));
//将对象序列化到文件filePath
outStream.writeObject(person);
2) xml 序列化
//序列化成xml
void XmlSerilize(TestSerilize testSerilize)
{
FileStream fileStream = new FileStream(Application.dataPath+"/Test.xml",FileMode.Create,FileAccess.ReadWrite,FileShare.ReadWrite);
StreamWriter sw = new StreamWriter(fileStream, System.Text.Encoding.UTF8);
XmlSerializer xml = new XmlSerializer(testSerilize.GetType());
xml.Serialize(sw, testSerilize);
sw.Close();
fileStream.Close();
}
xml log:
2011-2-20 0:00:00
20
......
3) json 序列化
var json = new { user = new { name = "fxhl", age = 23 }};
7 string jsonData = JsonConvert.SerializeObject(json);
8 Console.WriteLine(jsonData);
json log
{
"timestamp": "2019-06-21T19:06:25.285730",
"level": "WARNING",
"name": "root",
"message": "Hello world."
}
json的解析详见:
java parse json string: https://blog.csdn.net/fdsafwagdagadg6576/article/details/79348141
GSon 实例和解析:https://blog.csdn.net/fdsafwagdagadg6576/article/details/86652218
4) protobuf 序列化
在.proto文件中定义对象。编译.protobuf生产java类,使用java类传输.
.proto文件
转换的 Java
源代码 = Protocol Buffer
类 + 消息对象类(含Builder
内部类)
消息对象类 是
Protocol Buffer
类的内部类
i) 定义.proto文件
message Person {
required string name = 1;
required int32 id = 2;
optional string email = 3;
enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message PhoneNumber {
required string number = 1;
optional PhoneType type = 2 [default = HOME];
}
repeated PhoneNumber phone = 4;
}
ii) 使用
// 步骤1:通过 消息类的内部类Builder类 构造 消息类的消息构造器
Demo.Person.Builder personBuilder = Demo.Person.newBuilder();
// 步骤2:设置你想要设置的字段为你选择的值
personBuilder.setName("Carson");// 在定义.proto文件时,该字段的字段修饰符是required,所以必须赋值
personBuilder.setId(123);// 在定义.proto文件时,该字段的字段修饰符是required,所以必须赋值
personBuilder.setEmail("[email protected]"); // 在定义.proto文件时,该字段的字段修饰符是optional,所以可赋值 / 不赋值(不赋值时将使用默认值)
Demo.Person.PhoneNumber.Builder phoneNumber = Demo.Person.PhoneNumber.newBuilder();
phoneNumber.setType( Demo.Person.PhoneType.HOME);// 直接采用枚举类型里的值进行赋值
phoneNumber.setNumber("0157-23443276");
// PhoneNumber消息是嵌套在Person消息里,可以理解为内部类
// 所以创建对象时要通过外部类来创建
// 步骤3:通过 消息构造器 创建 消息类 对象
Demo.Person person = personBuilder.build();
// 步骤4:序列化和反序列化消息(两种方式)
/*方式1:直接 序列化 和 反序列化 消息 */
// a.序列化
byte[] byteArray1 = person.toByteArray();
// 把 person消息类对象 序列化为 byte[]字节数组
System.out.println(Arrays.toString(byteArray1));
// 查看序列化后的字节流
/*方式2:通过输入/ 输出流(如网络输出流) 序列化和反序列化消息 */
// a.序列化
ByteArrayOutputStream output = new ByteArrayOutputStream();
try {
person.writeTo(output);
// 将消息序列化 并写入 输出流(此处用 ByteArrayOutputStream 代替)
}
protobuffer封装方法:https://blog.51cto.com/9291927/2332264.
protobuffer使用:https://www.jianshu.com/p/4575342bc8ad
五 Serializable二进制,xml,json,protobuffer的区别
**1) 二进制和xml的区别? **
这个问题也是为什么要用序列化。
i) 持久化
对象二进制存成文件,用户没法看懂。
ii)网络和进程传输
二进制传输,变量没有边界符号,不知道每个域的意义。所以双方传输struct的每个item顺序必须是固定的,不利于扩展。
xml 使用xml lib传输,采用key-value方式。读写根据key就可以找到value,所以不用固定顺序,方便扩展。
2) protobuffer和json比较
protobuf优化了编码方式,造成传输更高效.
双方定义proto文件,都有message person定义,所以不用传字符串string,传序号即可。比如:传name需要4个字节,传数字1,1个字节即可。
图片引用自陶辉blog.
3) protobuffer,json,xml 区别?
三者都是key-value. json优化了xml的树形结构,protobuffer继续优化了json的key部分.
解析xml也麻烦,用树形结构。一层一层解析。不像protobuffer,直接变量获取。
QA 反序列化是用反射实现的
jdk1.8源码,readObject-> readObject0 -> readOrdinaryObject -> invokeReadResolve->readResolveMethod.invoke
aidl 和protobuf区别
双方使用方法有些相似,都是定义接口,自动生成java类文件,使用java类. 但是作用完全不同,protobuf类似xml是一种传输格式,而aidl类似socket是一种进程通信方式.
六 Parcel
Intent 使用parcel做组件通信:[https://www.jianshu.com/p/ae1aa13a3f51]
Serializable,Parcel区别? Parcel 是 android专用.优化了序列化,serializable序列化需要大量临时变量,parcel不需要。网上测试速度parcel是serializable速度的10倍。
Parcel和binder关系? Binder都是用parcel数据传输.
client: intent.writeToParcel(data, 0)//Intent 写parcel; mRemote.transact //binder client 发送
server: onTransact //binder server 接收; Intent intent = Intent.CREATOR.createFromParcel(data); //打开parcel提取Intent.
实例如下:
Client:
public int startActivity(IApplicationThread caller, String callingPackage, ..) {
//Parcel池中获取两个Parcel对象
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
...
data.writeString(callingPackage);
intent.writeToParcel(data, 0);//用于写入自己传递的数据
data.writeStrongBinder(resultTo); mRemote.transact(START_ACTIVITY_TRANSACTION,data,reply,0);...//写入数据到data后,远程通信
}
Server:
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
switch (code) {
case SCHEDULE_LAUNCH_ACTIVITY_TRANSACTION:
//创建Intent.
Intent intent = Intent.CREATOR.createFromParcel(data);
IBinder b = data.readStrongBinder();
int ident = data.readInt();
ActivityInfo info = ActivityInfo.CREATOR.createFromParcel(data);
...
//该方法在ActivityThread中定义的ApplicationThread实体实现.
scheduleLaunchActivity(intent, b, ident, info, ....);
return true;
}
}
Parcel 原理:
扩展阅读:
Serializable是怎么一回事 https://juejin.cn/post/6850418112501268494 ----Serializable 源码分析