Android为什么提供2个用于序列化对象的接口?可序列化对象与Android Binder
和AIDL文件互斥吗?
Android为什么提供2个用于序列化对象的接口?可序列化对象与Android Binder
和AIDL文件互斥吗?
Answers:
在Android中,我们不能仅将对象传递给活动。为此,对象必须实现Serializable
或Parcelable
接口。
可序列化
Serializable
是标准的Java接口。您可以只实现Serializable
接口并添加重写方法。这种方法的问题在于使用了反射,这是一个缓慢的过程。此方法会创建许多临时对象,并导致大量垃圾回收。然而,Serializable
接口更易于实现。
请看下面的示例(可序列化):
// MyObjects Serializable class
import java.io.Serializable;
import java.util.ArrayList;
import java.util.TreeMap;
import android.os.Parcel;
import android.os.Parcelable;
public class MyObjects implements Serializable {
private String name;
private int age;
public ArrayList<String> address;
public MyObjects(String name, int age, ArrayList<String> address) {
super();
this.name = name;
this.age = age;
this.address = address;
}
public ArrayList<String> getAddress() {
if (!(address == null))
return address;
else
return new ArrayList<String>();
}
public String getName() {
return name;
}
public String getAge() {
return age;
}
}
// MyObjects instance
MyObjects mObjects = new MyObjects("name", "age", "Address array here");
// Passing MyObjects instance via intent
Intent mIntent = new Intent(FromActivity.this, ToActivity.class);
mIntent.putExtra("UniqueKey", mObjects);
startActivity(mIntent);
// Getting MyObjects instance
Intent mIntent = getIntent();
MyObjects workorder = (MyObjects) mIntent.getSerializableExtra("UniqueKey");
可包裹
Parcelable
过程比Serializable
。原因之一是我们对序列化过程很明确,而不是使用反射来推断它。也有理由为此目的对代码进行了大幅优化。
请看下面的示例(可拆分):
// MyObjects Parcelable class
import java.util.ArrayList;
import android.os.Parcel;
import android.os.Parcelable;
public class MyObjects implements Parcelable {
private int age;
private String name;
private ArrayList<String> address;
public MyObjects(String name, int age, ArrayList<String> address) {
this.name = name;
this.age = age;
this.address = address;
}
public MyObjects(Parcel source) {
age = source.readInt();
name = source.readString();
address = source.createStringArrayList();
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(age);
dest.writeString(name);
dest.writeStringList(address);
}
public int getAge() {
return age;
}
public String getName() {
return name;
}
public ArrayList<String> getAddress() {
if (!(address == null))
return address;
else
return new ArrayList<String>();
}
public static final Creator<MyObjects> CREATOR = new Creator<MyObjects>() {
@Override
public MyObjects[] newArray(int size) {
return new MyObjects[size];
}
@Override
public MyObjects createFromParcel(Parcel source) {
return new MyObjects(source);
}
};
}
// MyObjects instance
MyObjects mObjects = new MyObjects("name", "age", "Address array here");
// Passing MyOjects instance
Intent mIntent = new Intent(FromActivity.this, ToActivity.class);
mIntent.putExtra("UniqueKey", mObjects);
startActivity(mIntent);
// Getting MyObjects instance
Intent mIntent = getIntent();
MyObjects workorder = (MyObjects) mIntent.getParcelableExtra("UniqueKey");
您可以ArrayList
按以下方式传递Parcelable对象:
// Array of MyObjects
ArrayList<MyObjects> mUsers;
// Passing MyOjects instance
Intent mIntent = new Intent(FromActivity.this, ToActivity.class);
mIntent.putParcelableArrayListExtra("UniqueKey", mUsers);
startActivity(mIntent);
// Getting MyObjects instance
Intent mIntent = getIntent();
ArrayList<MyObjects> mUsers = mIntent.getParcelableArrayList("UniqueKey");
结论
Parcelable
比Serializable
界面快Parcelable
与Serializable
接口相比,接口需要更多的时间来实现Serializable
界面更易于实现 Serializable
接口会创建很多临时对象,并导致大量垃圾回收Parcelable
数组可以在Android中通过Intent传递可序列化是标准的Java接口。您只需通过实现接口将一个类标记为Serializable即可,Java在某些情况下会自动对其进行序列化。
可包裹是Android专用的界面,您可以在其中实现序列化。它的创建要比Serializable效率高得多,并且可以解决默认Java序列化方案中的一些问题。
我相信Binder和AIDL可用于Parcelable对象。
但是,您可以在Intent中使用Serializable对象。
对于Java和Kotlin
1)Java
可序列化,简单
什么是可序列化的?
可序列化是标准的Java接口。它不是Android SDK的一部分。它的简单就是它的美丽。只需实现此接口,您的POJO就可以从一个Activity跳到另一个Activity了。
public class TestModel implements Serializable {
String name;
public TestModel(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
可序列化的优点在于,您只需要在类及其子类上实现Serializable接口。这是一个标记器接口,这意味着没有实现方法,Java会尽最大努力有效地序列化它。
这种方法的问题在于使用了反射,这是一个缓慢的过程。这种机制还倾向于创建许多临时对象,并导致大量垃圾回收。
可包裹的速度
什么是可包裹的?
可打包是另一个接口。尽管有竞争对手(如果您忘记了,则可以序列化),它是Android SDK的一部分。现在,Parcelable经过专门设计,使用时不会反射。那是因为我们对序列化过程确实很明确。
public class TestModel implements Parcelable {
String name;
public TestModel(String name, String id) {
this.name = name;
}
protected TestModel(Parcel in) {
this.name = in.readString();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(this.name);
}
public static final Parcelable.Creator<TestModel> CREATOR = new Parcelable.Creator<TestModel>() {
@Override
public TestModel createFromParcel(Parcel source) {
return new TestModel(source);
}
@Override
public TestModel[] newArray(int size) {
return new TestModel[size];
}
};
}
现在,赢家是
Philippe Breault进行的测试结果表明,Parcelable比Serializable快10倍以上。其他一些Google工程师也支持该声明。
他们认为,默认的Serializable方法比Parcelable慢。双方在这里达成协议!但是,完全将这两者进行比较是不公平的!因为使用Parcelable,我们实际上是在编写自定义代码。专为该POJO创建的代码。因此,不会产生垃圾,效果会更好。但是,使用默认的Serializable方法,我们依赖Java的自动序列化过程。该过程显然不是自定义的,会产生大量垃圾!因此,结果更糟。
停止停止!!!!,在做出决定之前
现在,有另一种方法。Serializable背后的整个自动过程可以由使用writeObject()和readObject()方法的自定义代码代替。这些方法是特定的。如果我们要依赖于可序列化方法与自定义序列化行为的结合,那么我们必须包括这两种方法,它们具有与以下方法完全相同的签名:
private void writeObject(java.io.ObjectOutputStream out)
throws IOException;
private void readObject(java.io.ObjectInputStream in)
throws IOException, ClassNotFoundException;
private void readObjectNoData()
throws ObjectStreamException;
现在,将Parcelable和自定义Serializable进行比较似乎很合理!结果可能令人惊讶!与Parcelable相比,自定义Serializable方法的写入速度要快3倍以上,读取速度要快1.6倍。
编辑:-----
2)Kotlinx序列化
Kotlinx 序列化库
For Kotlin serialization need to add below dependency and plugin
implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime:0.9.1"
apply plugin: 'kotlinx-serialization'
您的build.gradle
档案
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlinx-serialization'
android {
compileSdkVersion 28
defaultConfig {
applicationId "com.example.smile.kotlinxretrosample"
minSdkVersion 16
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime:0.9.1"
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
implementation 'com.android.support:design:28.0.0'
implementation 'com.squareup.retrofit2:retrofit:2.5.0'
implementation 'com.squareup.okhttp3:okhttp:3.12.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}
序列化非常容易完成,您需要使用以下注释对预期的类进行@Serializable
注释
import kotlinx.serialization.Serializable
@Serializable
class Field {
var count: Int = 0
var name: String = ""
}
还有两个要注意的注释是transient
和optional
。使用暂态将使序列化程序忽略该字段,而使用可选将允许序列化程序在缺少字段的情况下不中断,但同时需要提供默认值。
@Optional
var isOptional: Boolean = false
@Transient
var isTransient: Boolean = false
注意:这也可以与数据类一起使用。
现在实际使用此功能,让我们举一个例子,说明如何将JSON转换为对象并返回
fun toObject(stringValue: String): Field {
return JSON.parse(Field.serializer(), stringValue)
}
fun toJson(field: Field): String {
//Notice we call a serializer method which is autogenerated from our class
//once we have added the annotation to it
return JSON.stringify(Field.serializer(), field)
}
欲了解更多
Serialization
,看看。
如果您想成为一个好公民,请花额外的时间来实施Parcelable,因为它的执行速度提高了10倍,并且使用的资源更少。
但是,在大多数情况下,Serializable的速度不会很明显。请随意使用它,但请记住,序列化是一项昂贵的操作,因此请尽量减少序列化。
如果您尝试传递包含数千个序列化对象的列表,则整个过程可能会花费一秒钟以上的时间。它可以使从肖像到风景的过渡或旋转非常缓慢。
到这一点的来源:http : //www.developerphil.com/parcelable-vs-serializable/
在Parcelable中,开发人员编写用于编组和拆组的自定义代码,因此与序列化相比,它创建的垃圾对象更少。由于采用了这种自定义实现,因此Parcelable over Serialization的性能大大提高了(快了大约两倍)。
可序列化是一个标记接口,这意味着用户无法根据自己的要求封送数据。在序列化中,使用Java反射API在Java虚拟机(JVM)上执行封送处理操作。这有助于识别Java对象的成员和行为,但最终会创建很多垃圾对象。因此,与可打包相比,序列化过程很慢。
编辑:编组和拆组是什么意思?
简而言之,“编组”是指将数据或对象inb转换为字节流的过程,而“解组”是将字节流beack转换为其原始数据或对象的相反过程。转换是通过“序列化”实现的。
我实际上将成为提倡Serializable的那个人。速度差异不再那么剧烈,因为这些设备比几年前要好得多,并且还存在其他更细微的差异。有关更多信息,请参阅我的博客文章。
建议使用Parcelable方法进行数据传输。但是,如果您如本存储库所示正确使用了可序列化,您将看到有时可序列化甚至比可打包更快。或者至少时间是可比的。
在一般的Android设备上,通常的Java序列化(如果操作正确*)比Parcelable快3.6倍,而读取则快1.6倍。它还证明了Java序列化(如果操作正确)是一种快速存储机制,即使在相对较大的对象图(包含11000个对象,每个对象包含10个字段)的情况下,也能给出可接受的结果。
*旁注是,通常每个人盲目声明“ Parcelable的速度更快”将其与默认的自动序列化进行比较,后者在内部使用了很多反射。这是不公平的比较,因为Parcelable使用手动(且非常复杂)的过程将数据写入流。通常没有提到的是,根据文档的标准Java Serializable也可以使用writeObject()和readObject()方法以手动方式完成。有关更多信息,请参见JavaDocs。这是应该如何做到最好的性能。
原因是本机代码。创建Parcelable不仅用于进程间通信。它也可以用于代码间通信。您可以从C ++本机层发送和接收对象。而已。
您应该选择什么?两者都会很好地工作。但是我认为Parcelable是更好的选择,因为它是Google推荐的,并且您可以从此线程中看到它,这一点值得赞赏。
@see http://docs.oracle.com/javase/7/docs/api/java/io/Serializable.html
@see http://developer.android.com/reference/android/os/Parcelable.html
请注意,Serializable是标准的Java接口,而Parcelable是用于Android开发的
关于封送和拆组存在一些性能问题。可打包的速度比可序列化的速度快两倍。
请通过以下链接:
http://www.3pillarglobal.com/insights/parcelable-vs-java-serialization-in-android-app-development
可序列化的接口可以与可打包的接口以相同的方式使用,从而导致(不多)更好的性能。只需覆盖这两种方法来处理手动编组和解组过程即可:
private void writeObject(java.io.ObjectOutputStream out)
throws IOException
private void readObject(java.io.ObjectInputStream in)
throws IOException, ClassNotFoundException
不过,在我看来,当开发本机Android时,使用Android api是必经之路。
见:
我的回答很晚,但是希望能对其他人有所帮助。
在方面的速度,Parcelable > Serializable
。但是,Custom Serializable是例外。它几乎处于Parcelable范围内,甚至更快。
参考:https : //www.geeksforgeeks.org/customized-serialization-and-deserialization-in-java/
范例:
自定义类要序列化
class MySerialized implements Serializable {
String deviceAddress = "MyAndroid-04";
transient String token = "AABCDS"; // sensitive information which I do not want to serialize
private void writeObject(ObjectOutputStream oos) throws Exception {
oos.defaultWriteObject();
oos.writeObject("111111" + token); // Encrypted token to be serialized
}
private void readObject(ObjectInputStream ois) throws Exception {
ois.defaultReadObject();
token = ((String) ois.readObject()).subString(6); // Decrypting token
}
}
可打包比使用Binder可序列化要快得多,因为可序列化使用反射并导致许多GC。可拆分设计旨在优化传递对象。
这里是参考链接。 http://www.developerphil.com/parcelable-vs-serializable/
可序列化
可序列化是一个可标记的接口,或者我们可以将其称为空接口。它没有任何预先实现的方法。可序列化将把一个对象转换为字节流。因此,用户可以在一个活动与另一个活动之间传递数据。可序列化的主要优点是创建和传递数据非常容易,但是与可打包相比,这是一个缓慢的过程。
可包裹
具有包裹功能比可序列化速度更快。Parcelable将把对象转换为字节流并在两个活动之间传递数据。与序列化相比,编写可打包的代码有点复杂。在两个活动之间传递数据时,它不会创建更多临时对象。