Android高级架构进阶之数据传输与序列化

  • 所谓的Serializable,就是java提供的通用数据保存和读取的接口。至于从什么地方读出来和保存到哪里去都被隐藏在函数参数的背后了。这样子,任何类型只要实现了Serializable接口,就可以被保存到文件中,或者作为数据流通过网络发送到别的地方。也可以用管道来传输到系统的其他程序中。这样子极大的简化了类的设计。只要设计一个保存一个读取功能就能解决上面说得所有问题。

  • java的"对象序列化"能让你将一个实现了Serializable接口的对象转换成一组byte,这样日后要用这个对象时候,你就能把这些byte数据恢复出来,并据此重新构建那个对象了。

  • 工作流当中流程变量的几种数据类型:string、integer、short、long、double、boolean、date、binary、serializable,这就是为什么要将javabean实现序列化的原因,因为你将对象设置到流程变量中必须要实现序列化,否则会在设置流程变量的时候报错找不到该类型。

  • java对象序列化机制就是把内存中的Java对象(User之类的JavaBean)转换成二进制流。java对象序列化后可以很方便的存储或者在网络中传输。

  • Java的序列化机制是通过运行时判断类的序列化ID(serialVersionUID)来判定版本的一致性。

  • 在反序列化时,java虚拟机会通过二进制流中的serialVersionUID与本地的对应的实体类进行比较,如果相同就认为是一致的,可以进行反序列化,正确获得信息,否则抛出序列化版本不一致的异常。

  • 所以涉及到数据传输或者存储的类,严格意义上来说都要加上序列化ID,这也是一种良好的编程习惯

二、Parcelable的原理和使用方法

=======================================================================================

###2.1 Android源码中的Parcelable

/**

  • Interface for classes whose instances can be written to

  • and restored from a {@link Parcel}. Classes implementing the Parcelable

  • interface must also have a non-null static field called CREATOR

  • of a type that implements the {@link Parcelable.Creator} interface.

  • A typical implementation of Parcelable is:

  • public class MyParcelable implements Parcelable {

  • private int mData;
    
  •   public int describeContents() {
    
  •     return 0;
    
  • }
    
  • public void writeToParcel(Parcel out, int flags) {
    
  •     out.writeInt(mData);
    
  • }
    
  • public static final Parcelable.Creator<MyParcelable> CREATOR
    
  •         = new Parcelable.Creator<MyParcelable>() {
    
  •     public MyParcelable createFromParcel(Parcel in) {
    
  •         return new MyParcelable(in);
    
  •     }
    
  •     public MyParcelable[] newArray(int size) {
    
  •         return new MyParcelable[size];
    
  •     }
    
  • };
    
  • private MyParcelable(Parcel in) {
    
  •     mData = in.readInt();
    
  • }
    
  • }

*/

通过源码中的介绍 可以知道,Parcelable接口的实现类是可以通过Parcel写入和恢复数据的,并且必须要有一个非空的静态变量 CREATOR,而且还给了一个例子,这样我们写起来就比较简单了,但是简单的使用并不是我们的最终目的,通过查看Android源码中Parcelable可以看出,Parcelable实现过程主要分为序列化,反序列化,描述三个过程,下面分别介绍下这三个过程。

2.2 Parcel的简介

在介绍之前我们需要先了解Parcel是什么?Parcel翻译过来是打包的意思,其实就是包装了我们需要传输的数据,然后在Binder中传输,也就是用于跨进程传输数据

简单来说,Parcel提供了一套机制,可以将序列化之后的数据写入到一个共享内存中,其他进程通过Parcel可以从这块共享内存中读出字节流,并反序列化成对象,下图是这个过程的模型。

Parcel可以包含原始数据类型(用各种对应的方法写入,比如writeInt(),writeFloat()等),可以包含Parcelable对象,它还包含了一个活动的IBinder对象的引用,这个引用导致另一端接收到一个指向这个IBinder的代理IBinder。

Parcelable通过Parcel实现了read和write的方法,从而实现序列化和反序列化

2.3 Parcelable中的三大过程介绍(序列化,反序列化,描述)

2.3.1 什么是序列化

序列化,表示将一个对象转换成可存储或可传输的状态。序列化后的对象可以在网络上进行传输,也可以存储到本地。

到这里,基本上关系都理清了,也明白简单的介绍和原理了,接下来在实现Parcelable之前,介绍下实现Parcelable的三大流程 .

[图片上传中…(image.png-73288d-1522235519935-0)]

我先把代码贴出来

public class Album implements Parcelable {

/**

  • 负责反序列化

*/

private static final Creator CREATOR = new Creator() {

/**

  • 从序列化对象中,获取原始的对象

  • @param source

  • @return

*/

@Override

public Album createFromParcel(Parcel source) {

return new Album(source);

}

/**

  • 创建指定长度的原始对象数组

  • @param size

  • @return

*/

@Override

public Album[] newArray(int size) {

return new Album[0];

}

};

private final String mId;

private final String mCoverPath;

private final String mDisplayName;

private final long mCount;

Album(String id, String coverPath, String displayName, long count) {

mId = id;

mCoverPath = coverPath;

mDisplayName = displayName;

mCount = count;

}

Album(Parcel source) {

mId = source.readString();

mCoverPath = source.readString();

mDisplayName = source.readString();

mCount = source.readLong();

}

/**

  • 描述

  • 返回的是内容的描述信息

  • 只针对一些特殊的需要描述信息的对象,需要返回1,其他情况返回0就可以

  • @return

*/

@Override

public int describeContents() {

return 0;

}

/**

  • 序列化

  • @param dest

  • @param flags

*/

@Override

public void writeToParcel(Parcel dest, int flags) {

dest.writeString(mId);

dest.writeString(mCoverPath);

dest.writeString(mDisplayName);

dest.writeLong(mCount);

}

2.3.2 实现Parcelable的作用

1)永久性保存对象,保存对象的字节序列到本地文件中;

2)通过序列化对象在网络中传递对象;

3)通过序列化在进程间传递对象。

首先写一个类实现Parcelable接口,会让我们实现两个方法:

  • describeContents 描述

其中describeContents就是负责文件描述.通过源码的描述可以看出,只针对一些特殊的需要描述信息的对象,需要返回1,其他情况返回0就可以

  • writeToParcel 序列化

我们通过writeToParcel方法实现序列化,writeToParcel返回了Parcel,所以我们可以直接调用Parcel中的write方法,基本的write方法都有,对象和集合比较特殊下面单独讲,基本的数据类型除了boolean其他都有,Boolean可以使用int或byte存储

我们将上面的Album对象实现序列化,Album对象包含四个字段。

2.3.4 反序列化

反序列化需要定义一个CREATOR的变量,上面也说了具体的做法,这里可以直接复制Android给的例子中的,也可以自己定义一个(名字千万不能改),通过匿名内部类实现Parcelable中的Creator的接口

2.4 Parcelable的使用和实现

根据上面三个过程的介绍,Parcelable就写完了,就可以直接在Intent中传输了,可以自己写两个Activity传输一下数据试一下,其中一个putExtra另一个getParcelableExtra即可。

2.5 Parcelable中对象和集合的处理

import android.os.Parcel;

import android.os.Parcelable;

import java.util.ArrayList;

/**

  • Created by fengxing on 2018/3/28.

*/

public class ParcelDemo implements Parcelable {

private int count;

private String name;

private ArrayList tags;

private Book book;

// ***** 注意: 这里如果是集合 ,一定要初始化 *****

private ArrayList books = new ArrayList<>();

/**

  • 序列化

  • @param in

*/

protected ParcelDemo(Parcel in) {

count = in.readInt();

name = in.readString();

tags = in.createStringArrayList();

// 读取对象需要提供一个类加载器去读取,因为写入的时候写入了类的相关信息

book = in.readParcelable(Book.class.getClassLoader());

//读取集合也分为两类,对应写入的两类

//这一类需要用相应的类加载器去获取

in.readList(books, Book.class.getClassLoader());// 对应writeList

//这一类需要使用类的CREATOR去获取

in.readTypedList(books, Book.CREATOR); //对应writeTypeList

//books = in.createTypedArrayList(Book.CREATOR); //对应writeTypeList

//这里获取类加载器主要有几种方式

getClass().getClassLoader();

Thread.currentThread().getContextClassLoader();

Book.class.getClassLoader();

}

public static final Creator CREATOR = new Creator() {

@Override

public ParcelDemo createFromParcel(Parcel in) {

return new ParcelDemo(in);

}

@Override

public ParcelDemo[] newArray(int size) {

return new ParcelDemo[size];

}

};

/**

  • 描述

  • @return

*/

@Override

public int describeContents() {

return 0;

}

/**

  • 反序列化

  • @param dest

  • @param flags

*/

@Override

public void writeToParcel(Parcel dest, int flags) {

dest.writeInt(count);

dest.writeString(name);

//序列化一个String的集合

dest.writeStringList(tags);

// 序列化对象的时候传入要序列化的对象和一个flag,

// 这里的flag几乎都是0,除非标识当前对象需要作为返回值返回,不能立即释放资源

dest.writeParcelable(book, 0);

// 序列化一个对象的集合有两种方式,以下两种方式都可以

//这些方法们把类的信息和数据都写入Parcel,以使将来能使用合适的类装载器重新构造类的实例.所以效率不高

dest.writeList(books);

//这些方法不会写入类的信息,取而代之的是:读取时必须能知道数据属于哪个类并传入正确的Parcelable.Creator来创建对象

// 而不是直接构造新对象。(更加高效的读写单个Parcelable对象的方法是:

// 直接调用Parcelable.writeToParcel()和Parcelable.Creator.createFromParcel())

dest.writeTypedList(books);

}

}

Book类,需要先实现Parcelable,实现步骤就不贴出来了,和普通的对象一样,实现三个过程

import android.os.Parcel;

import android.os.Parcelable;

/**

  • Created by fengxing on 2018/3/28.

*/

public class Book implements Parcelable {

protected Book(Parcel in) {

}

public static final Creator CREATOR = new Creator() {

@Override

public Book createFromParcel(Parcel in) {

return new Book(in);

}

@Override

public Book[] newArray(int size) {

return new Book[size];

}

};

@Override

public int describeContents() {

return 0;

}

@Override

public void writeToParcel(Parcel dest, int flags) {

}

}

写入和读取集合有两种方式,

一种是写入类的相关信息,然后通过类加载器去读取, –> writeList | readList

二是不用类相关信息,创建时传入相关类的CREATOR来创建 –> writeTypeList | readTypeList | createTypedArrayList

第二种效率高一些

一定要注意如果有集合定义的时候一定要初始化 like this –>

public ArrayList<T> demo = new ArrayList<>();

2.6 Parcelable和Serializable的区别和比较

Parcelable和Serializable都是实现序列化并且都可以用于Intent间传递数据,Serializable是Java的实现方式,可能会频繁的IO操作,所以消耗比较大,但是实现方式简单 Parcelable是Android提供的方式,效率比较高,但是实现起来复杂一些 , 二者的选取规则是:内存序列化上选择Parcelable, 存储到设备或者网络传输上选择Serializable(当然Parcelable也可以但是稍显复杂)

####2.6.1 选择序列化方法的原则

1)在使用内存的时候,Parcelable比Serializable性能高,所以推荐使用Parcelable。

2)Serializable在序列化的时候会产生大量的临时变量,从而引起频繁的GC。

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

最后的最后

对于程序员来说,要学习的知识内容、技术有太多太多,要想不被环境淘汰就只有不断提升自己,从来都是我们去适应环境,而不是环境来适应我们!

当你有了学习线路,学习哪些内容,也知道以后的路怎么走了,理论看多了总要实践的

最后,互联网不存在所谓的寒冬,只是你没有努力罢了!

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

g-DTt9ZqiW-1712604269993)]

[外链图片转存中…(img-xrbCN2bi-1712604269993)]

[外链图片转存中…(img-owsRJ4lL-1712604269994)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

最后的最后

对于程序员来说,要学习的知识内容、技术有太多太多,要想不被环境淘汰就只有不断提升自己,从来都是我们去适应环境,而不是环境来适应我们!

当你有了学习线路,学习哪些内容,也知道以后的路怎么走了,理论看多了总要实践的

[外链图片转存中…(img-n0bCpZ6Q-1712604269994)]

最后,互联网不存在所谓的寒冬,只是你没有努力罢了!

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值