Android:可拆分和可序列化之间的区别?


Answers:


444

在Android中,我们不能仅将对象传递给活动。为此,对象必须实现SerializableParcelable接口。

可序列化

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");

结论

  1. ParcelableSerializable界面快
  2. ParcelableSerializable接口相比,接口需要更多的时间来实现
  3. Serializable 界面更易于实现
  4. Serializable 接口会创建很多临时对象,并导致大量垃圾回收
  5. Parcelable 数组可以在Android中通过Intent传递

2
@Sujith 使用反射是什么意思?什么是反射
2016年

11
@AbhinavVutukuri反射是用于在运行时通过Object.getClass()等检查对象,字段和方法的术语。
FaultException

2
可序列化的对象更适合持久化数据,而可打包对象则根本不应该持久化。这是一个非常糟糕的做法
TheAnimatrix

2
@Sujith如不止一个人所述,Parcelable对象不能(可靠地)持久化,而Serializable对象可以(在限制范围内)持久化。由于您的答案得分最高,并且给人的印象是涵盖所有重要差异,因此您可能应该提到这一点。
LarsH '17

4
现在,Parcelable的实现与Serializable一样快,只需在Android Studio中任何实现Parcelable的类上按ALT + INSERT,IDE就会做到。
阿里·尼姆

183

可序列化是标准的Java接口。您只需通过实现接口将一个类标记为Serializable即可,Java在某些情况下会自动对其进行序列化。

可包裹是Android专用的界面,您可以在其中实现序列化。它的创建要比Serializable效率高得多,并且可以解决默认Java序列化方案中的一些问题。

我相信Binder和AIDL可用于Parcelable对象。

但是,您可以在Intent中使用Serializable对象。


1
如何序列化一个Parcelable对象?我如何使其持久?
哈德斯

@Haded获取对象状态的内容,并将其存储在文件或SQLLite数据库中。序列化有助于使对象在android或不同应用程序中的不同组件之间完全可转移。
乔纳森

6
这是一个很好的解释。我还注意到了这一点:“ Parcel不是通用的序列化机制。此类(以及用于将任意对象放入Parcel的相应Parcelable API)被设计为高性能IPC传输。因此,它不适合用于将任何Parcel数据放入永久性存储中:对Parcel中任何数据的基本实现进行更改都会使较旧的数据变得不可读。” developer.android.com/reference/android/os/Parcel.html
Sam003年

@Zhisheng任意对象是什么意思?我们可以放入包裹中的哪种物品?
hasnain_ahmad 2015年

如何使用gson将对象转换为json字符串呢?
FOO 2016年

57

可拆分与可序列化我将引用这两个。

对于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 = ""
}

还有两个要注意的注释是transientoptional。使用暂态将使序列化程序忽略该字段,而使用可选将允许序列化程序在缺少字段的情况下不中断,但同时需要提供默认值。

@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)
    }

欲了解更多


@Farhana如何在Kotlin中实现数据类?
Nisarg

@Nisarg我添加了Kotlin Serialization,看看。
Farhana

@Farhana这很有见地。我确实想在工作中搬到科特林,但我的建议一直被管理者拒绝。我想知道我能否获得Serializable(使用自定义方法)的基准,您说它比Parcelable快1.6倍。
Abhinav Kulshreshtha

39

如果您想成为一个好公民,请花额外的时间来实施Parcelable,因为它的执行速度提高了10倍,并且使用的资源更少。

但是,在大多数情况下,Serializable的速度不会很明显。请随意使用它,但请记住,序列化是一项昂贵的操作,因此请尽量减少序列化。

如果您尝试传递包含数千个序列化对象的列表,则整个过程可能会花费一秒钟以上的时间。它可以使从肖像到风景的过渡或旋转非常缓慢。

到这一点的来源:http : //www.developerphil.com/parcelable-vs-serializable/


32

在Parcelable中,开发人员编写用于编组和拆组的自定义代码,因此与序列化相比,它创建的垃圾对象更少。由于采用了这种自定义实现,因此Parcelable over Serialization的性能大大提高了(快了大约两倍)。

可序列化是一个标记接口,这意味着用户无法根据自己的要求封送数据。在序列化中,使用Java反射API在Java虚拟机(JVM)上执行封送处理操作。这有助于识别Java对象的成员和行为,但最终会创建很多垃圾对象。因此,与可打包相比,序列化过程很慢。

编辑:编组和拆组是什么意思?

简而言之,“编组”是指将数据或对象inb转换为字节流的过程,而“解组”是将字节流beack转换为其原始数据或对象的相反过程。转换是通过“序列化”实现的。

http://www.jguru.com/faq/view.jsp?EID=560072


即使没有冗长的示例,也相当不错的解释。正是我需要修订的内容。
sud007 '17

20

我实际上将成为提倡Serializable的那个人。速度差异不再那么剧烈,因为这些设备比几年前要好得多,并且还存在其他更细微的差异。有关更多信息,请参阅我的博客文章。


1
感谢您的分享。实现可序列化的过程不太复杂,需要在那些罕见的超优化情况下决定权衡。
Ankan-Zerob 2015年

2
另一种观点尤其是在获得实验和结果支持的情况下非常有帮助。我必须使用许多现有的基于Parcelable的源代码,并且在阅读您的博客文章之后可能会重构其中的一些源代码。
莱斯

14

Parcelable是Android开发中的一种标准。但不是因为速度

建议使用Parcelable方法进行数据传输。但是,如果您如本存储库所示正确使用了可序列化,您将看到有时可序列化甚至比可打包更快。或者至少时间是可比的。

可打包的速度快于可序列化的速度吗?

在一般的Android设备上,通常的Java序列化(如果操作正确*)比Parcelable快3.6倍,而读取则快1.6倍。它还证明了Java序列化(如果操作正确)是一种快速存储机制,即使在相对较大的对象图(包含11000个对象,每个对象包含10个字段)的情况下,也能给出可接受的结果。

*旁注是,通常每个人盲目声明“ Parcelable的速度更快”将其与默认的自动序列化进行比较,后者在内部使用了很多反射。这是不公平的比较,因为Parcelable使用手动(且非常复杂)的过程将数据写入流。通常没有提到的是,根据文档的标准Java Serializable也可以使用writeObject()和readObject()方法以手动方式完成。有关更多信息,请参见JavaDocs。这是应该如何做到最好的性能。

那么,如果可序列化更快,更容易实现,为什么android完全具有可打包性?

原因是本机代码。创建Parcelable不仅用于进程间通信。它也可以用于代码间通信。您可以从C ++本机层发送和接收对象。而已。

您应该选择什么?两者都会很好地工作。但是我认为Parcelable是更好的选择,因为它是Google推荐的,并且您可以从此线程中看到它,这一点值得赞赏。


您可以找到您的资源吗?我真的很感激。谢谢!!
Archie G.Quiñones19年

2
我从经验丰富的开发人员那里得到了这个答案,他从事与AOSP相关的项目twitter.com/bwdude。他说,用于与SDK层通信的本地C ++代码使用其自己的Parcelable实现。我猜他谈论这个类android.googlesource.com/platform/frameworks/native/+/... 我知道这是不是最好的解释,但它是我现在所拥有的最好的。如果您还有其他发现,请务必在此处发布=)
Maksim Turaev,

希望我能多次投票给您。我已经看到出色的Android和Java专家在这里寻求最受好评的答案。缺乏文档确实阻止了Serializable的关注。这样的感觉是提升特定API的效果。谢谢!
pulp_fiction19年

11

1.可序列化

@see http://docs.oracle.com/javase/7/docs/api/java/io/Serializable.html

接口是什么?

  • 是标准的Java接口

速度

  • 比包裹慢

2.可包裹

@see http://developer.android.com/reference/android/os/Parcelable.html

接口是什么?

  • 是android.os界面
    • 这意味着Google开发了Parcelable,以在Android上获得更好的性能

速度

  • 更快(因为它已针对Android开发进行了优化)

>结论

请注意,Serializable是标准的Java接口,而Parcelable是用于Android开发的


您也应该添加它们的用途。
Anshul Tyagi


4

如果您在android studio中使用paracelable插件,则parcelable的实现会更快。搜索Android Parcelable代码生成器


3

可序列化的接口可以与可打包的接口以相同的方式使用,从而导致(不多)更好的性能。只需覆盖这两种方法来处理手动编组和解组过程即可:

private void writeObject(java.io.ObjectOutputStream out)
    throws IOException
private void readObject(java.io.ObjectInputStream in)
    throws IOException, ClassNotFoundException

不过,在我看来,当开发本机Android时,使用Android api是必经之路。

见:


2

我的回答很晚,但是希望能对其他人有所帮助。

在方面的速度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
    }

}


1

您可以在意图中使用可序列化的对象,但是在序列化Parcelable对象时,它会产生严重的异常,例如NotSerializableException。不建议与Parcelable一起使用serializable。因此,最好使用要与bundle和intent一起使用的对象扩展Parcelable。由于此Parcelable是Android特定的,因此没有任何副作用。:)


0

可序列化

可序列化是一个可标记的接口,或者我们可以将其称为空接口。它没有任何预先实现的方法。可序列化将把一个对象转换为字节流。因此,用户可以在一个活动与另一个活动之间传递数据。可序列化的主要优点是创建和传递数据非常容易,但是与可打包相比,这是一个缓慢的过程。

可包裹

具有包裹功能比可序列化速度更快。Parcelable将把对象转换为字节流并在两个活动之间传递数据。与序列化相比,编写可打包的代码有点复杂。在两个活动之间传递数据时,它不会创建更多临时对象。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.