序列化Serializable\Parcel\xml\json\protobuffer

目录

image

一 序列化定义

一种用于传输对象的数据格式.
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();
  1. 网络
in = new java.io.ObjectInputStream(socket.getInputStream());
Java Serializable序列化Socket传送例子  http://blog.chinaunix.net/uid-14767524-id-3399136.html
  1. 进程
//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

  1. 二进制序列化**
    定义对象(要传输的对象)
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个字节即可。

image

image

图片引用自陶辉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 原理:

image

扩展阅读:
Serializable是怎么一回事 https://juejin.cn/post/6850418112501268494 ----Serializable 源码分析

你可能感兴趣的:(序列化Serializable\Parcel\xml\json\protobuffer)