android对象序列化Parcelable浅析

一、android序列化简介

我们已经知道在Android使用Intent/Bindler进行IPC传输数据时,需要将对象进行序列化。

JAVA原本已经提供了Serializable接口来实现序列化,使用起来非常简单,主要用于对象持久化以及对象的网络传输。Serializable开销比较大,因为序列化和反序列化的过程需要大量的I/O操作。

Android提供了Parcelable对象序列化操作是内存序列化,主要用于Intent/Bindler的IPC数据传输。

二、Parcelable序列化使用方法

比如我们使用Parcelable在两个activity直接通过intent进行传输一个Book的对象。

 1 package org.xerrard.demo2;
 2
 3 import android.os.Parcel;
 4 import android.os.Parcelable;
 5
 6 /**
 7  * Created by xuqiang on 16-1-20.
 8  */
 9 public class Book implements Parcelable{
10
11     public String bookname;
12
13     public Book(String bookname){
14         this.bookname = bookname;
15     }
16
17     protected Book(Parcel in) {
18         bookname = in.readString();
19     }
20
21     public static final Creator<Book> CREATOR = new Creator<Book>() {
22         @Override
23         public Book createFromParcel(Parcel in) {
24             return new Book(in);
25         }
26
27         @Override
28         public Book[] newArray(int size) {
29             return new Book[size];
30         }
31     };
32
33     @Override
34     public int describeContents() {
35         return 0;
36     }
37
38     @Override
39     public void writeToParcel(Parcel dest, int flags) {
40         dest.writeInt(bookname);
41     }
42 }

我们需要完成以下几部。

1. 实现Parcelable接口 
2. 添加实体属性 
3. 覆写writeToParcel(Parcel dest, int flags)方法,指定写入Parcel类的数据。 
4. 创建Parcelable.Creator静态对象,有两个方法createFromParcel(Parcel in)与newArray(int size),前者指定如何从Parcel中读取出数据对象,后者创建一个数组。 
5. 覆写describeContents方法,默认返回0。

然后我们就可以使用Intent中的putExtra方法将Book对象写入Intent中,然后使用getExtra方法,就可以从Intent中读出Book对象。

三、Parcelable底层序列化原理

从上面的例子可以看到,Parcelable的序列化方式使用起来还是比较麻烦的。但是,这种方式效率上是比较好的,因为Parcelable的序列化过程是再底层native通过内存操作实现的。

详细的JNI和C/C++底层的内存操作可以看这篇文章探索Android中的Parcel机制(上)

摘抄里面最重要的一句结论

整个读写全是在内存中进行,主要是通过malloc()、realloc()、memcpy()等内存操作进行,所以效率比JAVA序列化中使用外部存储器会高很多

因此,在IPC过程中,android推荐使用Parcelable序列化方式

四:Parcelable的调用关系

我们知道如果要使用Parcelable,必须按照要求实现这五项操作

1. 实现Parcelable接口 
2. 添加实体属性 
3. 覆写writeToParcel(Parcel dest, int flags)方法,指定写入Parcel类的数据。 
4. 创建Parcelable.Creator静态对象,有两个方法createFromParcel(Parcel in)与newArray(int size),前者指定如何从Parcel中读取出数据对象,后者创建一个数组。 
5. 覆写describeContents方法,默认返回0。

这里面又是怎样的调用关系呢?

我们看到,writeToParcel是在startActivity的过程中由intent->Bundle->Parcel 一步一步的调用的,然后WriteToParcel会调用native方法,在底层做序列化操作

而createFromParcel是在收到Intent之后,由Intent->Bundle->Parcel 一步一步的调用。

由此可以看出,Parcel的填包解包都是离不开Bundle的。

这里其实还是有一个疑问,这个Creator是怎么一回事呢?

我们从源码中截取Creator这部分来看看。

 1     public final <T extends Parcelable> T readParcelable(ClassLoader loader) {
 2         Parcelable.Creator<T> creator = readParcelableCreator(loader);
 3         if (creator == null) {
 4             return null;
 5         }
 6         if (creator instanceof Parcelable.ClassLoaderCreator<?>) {
 7             return ((Parcelable.ClassLoaderCreator<T>)creator).createFromParcel(this, loader);
 8         }
 9         return creator.createFromParcel(this);
10     }
11
12     /** @hide */
13     public final <T extends Parcelable> T readCreator(Parcelable.Creator<T> creator,
14             ClassLoader loader) {
15         if (creator instanceof Parcelable.ClassLoaderCreator<?>) {
16             return ((Parcelable.ClassLoaderCreator<T>)creator).createFromParcel(this, loader);
17         }
18         return creator.createFromParcel(this);
19     }
20
21     /** @hide */
22     public final <T extends Parcelable> Parcelable.Creator<T> readParcelableCreator(
23             ClassLoader loader) {
24         String name = readString(); //此处获得类名,还不太清楚如何获得的,如果想深入学习可以再研究
25         if (name == null) {
26             return null;
27         }
28         Parcelable.Creator<T> creator;
29         synchronized (mCreators) {
30             HashMap<String,Parcelable.Creator> map = mCreators.get(loader);
31             if (map == null) {
32                 map = new HashMap<String,Parcelable.Creator>();
33                 mCreators.put(loader, map);
34             }
35             creator = map.get(name);
36             if (creator == null) {
37                 try {
38                     Class c = loader == null ?
39                         Class.forName(name) : Class.forName(name, true, loader);
40                     Field f = c.getField("CREATOR");
41                     creator = (Parcelable.Creator)f.get(null);
42                 }
43                 catch (IllegalAccessException e) {
44                     Log.e(TAG, "Illegal access when unmarshalling: "
45                                         + name, e);
46                     throw new BadParcelableException(
47                             "IllegalAccessException when unmarshalling: " + name);
48                 }
49                 catch (ClassNotFoundException e) {
50                     Log.e(TAG, "Class not found when unmarshalling: "
51                                         + name, e);
52                     throw new BadParcelableException(
53                             "ClassNotFoundException when unmarshalling: " + name);
54                 }
55                 catch (ClassCastException e) {
56                     throw new BadParcelableException("Parcelable protocol requires a "
57                                         + "Parcelable.Creator object called "
58                                         + " CREATOR on class " + name);
59                 }
60                 catch (NoSuchFieldException e) {
61                     throw new BadParcelableException("Parcelable protocol requires a "
62                                         + "Parcelable.Creator object called "
63                                         + " CREATOR on class " + name);
64                 }
65                 catch (NullPointerException e) {
66                     throw new BadParcelableException("Parcelable protocol requires "
67                             + "the CREATOR object to be static on class " + name);
68                 }
69                 if (creator == null) {
70                     throw new BadParcelableException("Parcelable protocol requires a "
71                                         + "Parcelable.Creator object called "
72                                         + " CREATOR on class " + name);
73                 }
74
75                 map.put(name, creator);
76             }
77         }
78
79         return creator;
80     }

重点看粗体部分的代码——真想大白:

在接收端收到parcel之后,解析的时候,会通过反射去获取对象的Creator,然后保存到一个hashmap中。然后调用Creator的createFromParcel方法来实现解包。

反射在源码中也是无处不在!

时间: 2024-10-13 02:08:26

android对象序列化Parcelable浅析的相关文章

Android对象序列化存储

序列化的对象需要实现Serializable接口或者时容器对象 /** * Save the object * * @param context context * @param ser serializable object * @param file cache file * @throws java.io.IOException IOException */ @SuppressWarnings("JavaDoc") public static boolean saveObject

Android 序列化对象接口Parcelable使用方法

什么是Parcelable ? Parcelable,定义了将数据写入Parcel,和从Parcel中读出的接口.一个实体(用类来表示),如果需要封装到消息中去,就必须实现这一接口,实现了这一接口,该实体就成为"可打包的"了. Parcelable 传递对象 Android序列化对象主要有两种方法: 1.实现Serializable接口,实现Serializable接口是JavaSE本身就支持的; 2.实现Parcelable接口,Parcelable是Android特有的功能,效率比

Android Studio添加Parcelable序列化小工具(快速提高开发效率)

Android Studio添加Parcelable序列化小工具(快速提高开发效率) Android Studio是google专门为开发Android提供的开发工具,在它内部可以直接的添加一些非常好用的开发小工具,这里就讲解怎样添加这些小工具,并且向大家推荐一个非常有用的对象传递时,必须要把对象序列化的接口Parcelable小工具; 这里先介绍下 Android中实现序列化的两个选择:一是实现Serializable接口(是JavaSE本身就支持的),一是实现Parcelable接口(是An

Android中序列化对象到XMl 和 XML反序列化为对象

package com.example.xmloperation; import java.io.File; import java.io.FileOutputStream; import java.util.ArrayList; import java.util.List; import java.util.Random; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; imp

Android Serializable与Parcelable原理与区别

一.序列化.反序列化是什么? (1) 名词解释 对象的序列化 : 把Java对象转换为字节序列并存储至一个储存媒介的过程.对象的反序列化:把字节序列恢复为Java对象的过程. (2) 序列化详细解释 对象的序列化涉及三个点关键点:Java对象.字节序列.存储. 1. Java对象的组成?Java对象包含变量与方法.但是序列与反序列化仅处理Java变量而不处理方法,序列与反序列化仅对数据进行处理. 2. 什么是字符序列?字符序列是两个词,字符是在计算机和电信领域中,字符(Character)是一个

几种Android数据序列化方案

一.引言 数据的序列化在Android开发中占据着重要的地位,无论是在进程间通信.本地数据存储又或者是网络数据传输都离不开序列化的支持.而针对不同场景选择合适的序列化方案对于应用的性能有着极大的影响. 从广义上讲,数据序列化就是将数据结构或者是对象转换成我们可以存储或者传输的数据格式的一个过程,在序列化的过程中,数据结构或者对象将其状态信息写入到临时或者持久性的存储区中,而在对应的反序列化过程中,则可以说是生成的数据被还原成数据结构或对象的过程. 这样来说,数据序列化相当于是将我们原先的对象序列

Android中的Parcelable接口

Android中的android.os.Parcelable接口用于替代Java序列化Serializable接口,Fragment以及Activtity之间都需要传递数据,有时甚至包含结构非常复杂的对象,这就需要先将这个对象序列化成二进制流,然后再进行传递了. 比如Fragment1向Fragment2传递数据,下面是Fragment1中创建Fragment2并传送数据的方法: Fragment2 fragment = new Fragment2(); Bundle bundle = new 

Android系统中Parcelable和Serializable的区别

进行Android开发的时候,我们都知道不能将对象的引用传给Activities或者Fragments,我们需要将这些对象放到一个Intent或者Bundle里面,然后再传递. 通过Android的API,我们知道有两种选择,即在传递对象时,需要对我们的对象进行 Parcelable 或者Serializable化.作为Java开发者,相信大家对Serializable 机制有一定了解,那为什么还需要 Parcelable呢? 为了回答这个问题,让我们分别来看看这两者的差异. Serializa

Android中的Parcelable接口和Serializable用法和区别

Parcelable接口: Interface for classes whose instances can be written to and restored from a Parcel. Classes implementing the Parcelable interface must also have a static field called CREATOR, which is an object implementing the Parcelable.Creator inter