去哪接单做网站,门户网站如何帮企业做宣传,如何用frontpage做网站,网页升级在线观看作为Android开发者#xff0c;我们经常需要在不同的组件(Activity、Service等)之间传输数据。这里的传输往往不仅仅是简单的数据复制#xff0c;还可能涉及跨进程的内存复制操作。当传输的数据量较大时#xff0c;这种操作可能会带来严重的性能问题。而Android系…
作为Android开发者我们经常需要在不同的组件(Activity、Service等)之间传输数据。这里的传输往往不仅仅是简单的数据复制还可能涉及跨进程的内存复制操作。当传输的数据量较大时这种操作可能会带来严重的性能问题。而Android系统为我们提供了Parcelable这一高效的序列化传输机制很好地解决了这一痛点。今天就让我们一起来探讪Parcelable的神奇之处。 一、Parcelable架构与原理 Parcelable是Android中一种高效的序列化机制用于实现进程间通信(IPC)中的对象传递。
Parcelable相对于Serializable的使用相对复杂一些但Parcelable的效率相对Serializable也高很多这一直是Google工程师引以为傲的Parcelable和Serializable的效率对比Parcelable vs Serializable号称快10倍的效率。
与Serializable接口不同Parcelable采用的是手工编码的方式序列化后的数据更为紧凑。系统将数据打包到一个全局内存区域中可供不同线程/进程共享访问。 1、Parcelable的设计理念
Parcelable的设计理念是在保证一定性能的前提下尽可能节省内存和CPU开销。
从架构上来看Parcelable涉及到了Binder驱动、Parcel容器和IPCThreadState等几个关键组件共同构成了高效的序列化通道: 1、Binder驱动
Binder驱动是Android的核心组件之一负责进程间的数据传输。它在内核层为每个进程维护了一块受保护的共享内存区域用于在进程间传递Parcelable对象。 2、Parcel容器
Parcel对象是存储序列化数据的临时载体。开发者需要先将对象写入Parcel中然后由Binder驱动完成Parcel在进程间的拷贝和传递。 3、IPCThreadState
IPCThreadState是一个线程私有数据结构负责在进程间管理请求和应答的Parcel对象数据。每个线程在与其他进程通信时都会使用自己的IPCThreadState实例。 4、Parcelable接口
Parcelable接口定义了将对象写入和从Parcel容器读取的抽象协议开发者需要手动实现这两个序列化方法。系统会按此协议完成对象的编码/解码操作。 序列化的基本流程如下:
当一个进程需要向另一个进程传输数据时会先初始化一个Parcel容器对象;将要传递的Parcelable对象通过writeToParcel()方法写入Parcel容器;Binder驱动从发送方进程拷贝这个Parcel容器到内核共享内存区域;接收方进程从共享内存区读取Parcel数据并通过Parcelable.Creator反序列化出原始对象;接收进程的目标组件(如Activity)即可使用这个反序列化出的对象数据。 整个过程无需经过Java层的序列化操作因此效率极高。Parcel容器采用面向流的编码格式存储数据格式紧凑内存占用小。
此外Parcelable的实现细节还包括:
支持平台默认Java数据类型的高效编解码;使用标志位压缩编码节省空间;引入Parcel窗口缓存加快读写效率;等等一系列优化手段。
从架构和流程上看Parcelable不仅拥有简单的接口定义而且在系统层得到了全方位的优化支持使其在Android世界中成为高效低耗的序列化标准。当然与之对应的是开发者必须自行编写序列化方法的工作量。但从性能的角度来看这一点工作量是完全值得的。 二、Parcelable接口的使用 要使用Parcelable需要自己实现这两个接口方法。
// 定义一个数据类MyData实现Parcelable接口
public class MyData implements Parcelable {private int id;private String name;private boolean isAdult;// 构造函数public MyData(int id String name boolean isAdult) {this.id id;this.name name;this.isAdult isAdult;}// 从Parcel反序列化时使用的特殊构造函数protected MyData(Parcel in) {id in.readInt();name in.readString();isAdult in.readByte() ! 0;}// writeToParcel方法将数据写入ParcelOverridepublic void writeToParcel(Parcel dest int flags) {dest.writeInt(id);dest.writeString(name);dest.writeByte((byte) (isAdult ? 1 : 0));}// 生成用于反序列的CREATOR对象public static final CreatorMyData CREATOR new CreatorMyData() {Overridepublic MyData createFromParcel(Parcel in) {return new MyData(in);}Overridepublic MyData[] newArray(int size) {return new MyData[size];}};// describeContents是一个内部接口标志Overridepublic int describeContents() {return 0;}// getter/setter ...
} 接着就可以通过Intent、Binder等方式传输这个Parcelable对象了。系统在底层会自动完成序列化和反序列化的工作。
// 使用示例传递Parcelable对象
public class MainActivity extends AppCompatActivity {Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 创建MyData对象MyData data new MyData(1 Jack true);// 使用Intent传递MyDataIntent intent new Intent(this SecondActivity.class);intent.putExtra(data data);startActivity(intent);}
}// 接收Parcelable对象
public class SecondActivity extends AppCompatActivity {Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_second);// 从Intent中取出MyData对象MyData data getIntent().getParcelableExtra(data);if (data ! null) {int id data.getId();String name data.getName();boolean isAdult data.isAdult();// 处理data...}}
}在这个例子中:
我们定义了一个MyData类实现了Parcelable接口。在MyData类中我们提供了一个用于Parcel反序列化的特殊构造函数以及writeToParcel和describeContents方法。同时生成了一个CREATOR对象用于从Parcel重构MyData实例。在MainActivity中我们创建了一个MyData对象并通过Intent将它传递给SecondActivity。在SecondActivity中我们从Intent中取出了MyData对象可以使用其中的数据。
通过这个案例你可以看到使用Parcelable传递一个自定义数据对象是非常简单的。只需要完成几个基本方法的实现就可以实现对象的高效序列化和反序列化。
与手动实现序列化和Binder传递相比使用Parcelable的代码更加简洁、安全并得到了系统级的性能优化。这就是Parcelable作为Android高效IPC解决方案的魅力所在。 三、Parcelable的使用场景 以下是Parcelable主要用于的数据传输场景以及结合案例代码演示和使用Parcelable的优点分析。
1、Activity间传递数据 当从一个Activity导航到另一个Activity时可以使用Intent携带数据。如果数据对象实现了Parcelable接口可以直接在Intent中使用。
// 创建Parcelable对象
MyData myData new MyData(Hello 123);// 通过Intent传递数据
Intent intent new Intent(CurrentActivity.this NextActivity.class);
intent.putExtra(MY_DATA_KEY myData);
startActivity(intent);在接收的Activity中
// 接收Parcelable数据
Intent intent getIntent();
MyData myData intent.getParcelableExtra(MY_DATA_KEY);2、Activity与Service传递数据 Parcelable也可以用于Activity和Service之间的数据传输。可以通过Intent发送数据到Service或者Service返回结果给Activity。
// Activity发送数据到Service
Intent serviceIntent new Intent(this MyService.class);
serviceIntent.putExtra(MY_DATA_KEY myData);
startService(serviceIntent);3、通过Binder传输数据 在使用AIDLAndroid Interface Definition Language定义服务时Parcelable可以用来在客户端和服务器之间传递数据。
// 在AIDL接口定义中
parcelable MyData;4、将对象保存在Bundle或保存实例状态 在Activity的生命周期中可以在onSaveInstanceState方法中使用Bundle保存Parcelable对象。
Override
public void onSaveInstanceState(Bundle outState) {super.onSaveInstanceState(outState);outState.putParcelable(MY_DATA_KEY myData);
}Override
public void onRestoreInstanceState(Bundle savedInstanceState) {super.onRestoreInstanceState(savedInstanceState);myData savedInstanceState.getParcelable(MY_DATA_KEY);
}四、Parcelable与Serializable的比较 与Java中的Serializable相比Parcelable有以下优势:
1、性能更优 Parcelable序列化后的码流要比Serializable小得多内存开销和CPU损耗也更低。
2、使用成本低 Parcelable无需使用反射只需手写几个方法即可。
3、没有安全隐患 Parcelable不会自动完成数据的深复制避免了Serializable可能带来的安全隐患。
当然其缺点是需要手动编码实现序列化逻辑并维护代码与类结构的同步工作量较高。而Serializable则可以自动完成序列化。 五、Parcelable的性能优化建议 尽管Parcelable已经相当高效但我们在实际使用时仍可以通过一些优化手段达到更佳的性能表现:
1、尽量使用标量类型 标量类型(int/long)可以直接通过writeInt/writeLong方法进行序列化性能较高。
2、减少自动装箱操作 避免对装箱对象进行序列化如Integer等。应直接使用基本类型。
3、编写高效的Parcelable方法 在writeToParcel方法中应先写入有效数据而不是创建临时对象。
4、启用Parcelable代码生成器 Parceler等工具可以自动生成Parcelable代码提高开发效率。 六、不得不提及的Bundler Parcelable的强大远不止于上述简单用法。在Android 10开始Google引入了Bundler框架可以将任意的应用程序数据自动打包成一个Parcelable的Bundle从而实现高效的跨进程通信。Bundler极大地简化了使用Parcelable的难度。
这一强大功能曾广受期待。令人惋惜的是Bundler目前的可用性和成熟度似乎还有待提高。但不可否认Google为我们展现了Parcelable在未来更大的应用前景。
无论是Android系统的Binder还是Chrome浏览器的IPC数据传输Parcelable都扮演着举足轻重的角色。它使得Android应用能够高效、安全地在进程间传输数据。面向未来或许Parcelable的序列化能力会不断增强甚至取代JVM的Serializable成为跨平台的数据序列化标准。让我们拭目以待吧!