Android: разница между Parcelable и Serializable?

313

Почему Android предоставляет 2 интерфейса для сериализации объектов? Сериализуемые объекты взаимодействуют с файлами Android Binderи AIDL?

live2dream95
источник

Ответы:

444

В 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

Parcelableпроцесс намного быстрее чем Serializable. Одна из причин этого заключается в том, что мы явно рассказываем о процессе сериализации, а не используем отражение для его вывода. Также понятно, что код был сильно оптимизирован для этой цели.

Посмотрите на пример ниже (Parcelable):

// 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. Parcelableбыстрее Serializableинтерфейса
  2. ParcelableИнтерфейс требует больше времени для реализации по сравнению с Serializableинтерфейсом
  3. Serializable интерфейс проще в реализации
  4. Serializable Интерфейс создает много временных объектов и вызывает немало мусора
  5. Parcelable массив может быть передан через Intent в Android
Суджит
источник
2
@ Что ты имеешь в виду, когда используется отражение ? Что такое отражение ?
AnV
11
@AbhinavVutukuri Reflection - это термин для проверки объектов, полей и методов во время выполнения через Object.getClass () и тому подобное.
FaultException
2
Сериализуемые лучше подходят для сохранения данных, с другой стороны, объекты, подлежащие передаче, вообще не должны сохраняться. Это действительно плохая практика
TheAnimatrix
2
@Sujith Как заявили несколько человек, объекты Parcelable не могут быть сохранены (надежно), но объекты Serializable могут (в определенных пределах). Поскольку ваш ответ имеет наивысший балл и создает впечатление, что он охватывает все важные различия, вам, вероятно, следует упомянуть этот момент.
LarsH
4
Теперь реализация Parcelable так же быстро, как и Serializable, просто нажмите ALT + INSERT на любом классе, реализующем Parcelable в Android Studio, и среда IDE сделает это.
Али Нем
183

Serializable - это стандартный интерфейс Java. Вы просто помечаете класс Serializable, реализуя интерфейс, и Java автоматически сериализует его в определенных ситуациях.

Parcelable - это специальный интерфейс для Android, где вы сами реализуете сериализацию. Он был создан, чтобы быть намного более эффективным, чем Serializable, и обойти некоторые проблемы со стандартной сериализационной схемой Java.

Я считаю, что Binder и AIDL работают с объектами Parcelable.

Однако вы можете использовать Сериализуемые объекты в Intents.

Шерил Саймон
источник
1
Как я могу сериализовать объект Parcelable? Как мне сделать это постоянным?
Аид
@Haded Получить содержимое состояния объекта и сохранить его в файле или базе данных SQLLite. Серилизинг полезен для переноса объектов между различными компонентами в Android или другими приложениями.
Джонатан
6
Это отличное объяснение. Я также заметил следующее: «Parcel не является механизмом сериализации общего назначения. Этот класс (и соответствующий API Parcelable для помещения произвольных объектов в Parcel) разработан как высокопроизводительный транспорт IPC. Как таковой, он не подходит для Поместите любые данные Parcel в постоянное хранилище: изменения в базовой реализации любых данных в Parcel могут сделать старые данные нечитаемыми. " developer.android.com/reference/android/os/Parcel.html
Sam003
@Zhisheng, что подразумевается под произвольными объектами? какие объекты мы можем положить в посылку?
hasnain_ahmad
Как насчет преобразования объектов в строку json вместо gson?
FOO
57

Parcelable vs Serializable Я называю эти два.

Для Явы и Котлина

1) Ява

Сериализуемый, Простота

Что такое Сериализуемый?

Serializable - это стандартный интерфейс Java. Он не является частью Android SDK. Его простота - это красота. Просто реализовав этот интерфейс, ваш POJO будет готов к переходу от одного занятия к другому.

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 заключается в том, что вам нужно реализовать интерфейс Serializable только для класса и его потомков. Это маркерный интерфейс, означающий, что метод для реализации не существует, Java просто сделает все возможное для его эффективной сериализации.

  • Проблема этого подхода заключается в том, что используется рефлексия, и это медленный процесс. Этот механизм также имеет тенденцию создавать много временных объектов и вызывать довольно много мусора.

Parcelable, Скорость

Что такое Parcelable?

Parcelable - это еще один интерфейс. Несмотря на своего конкурента (Serializable на случай, если вы забыли), он является частью 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];
    }
};
}

Теперь победитель

введите описание изображения здесь

Результаты тестов, проведенных Филиппом Брео, показывают, что Parcelable более чем в 10 раз быстрее, чем Serializable. Некоторые другие инженеры Google также поддерживают это заявление.

Согласно им, подход Serializable по умолчанию медленнее, чем Parcelable. И здесь у нас есть соглашение между двумя сторонами! НО, несправедливо сравнивать эти два вообще! Потому что с Parcelable мы на самом деле пишем собственный код. Код, специально созданный для этого POJO. Таким образом, мусор не создается, и результаты лучше. Но с подходом Serializable по умолчанию мы полагаемся на процесс автоматической сериализации Java. Этот процесс, по-видимому, не является обычным и создает много мусора! Таким образом, худшие результаты.

Стоп Стоп !!!!, прежде чем принимать решение

Теперь есть другой подход . Весь автоматический процесс Serializable может быть заменен пользовательским кодом, который использует методы writeObject () и readObject (). Эти методы специфичны. Если мы хотим опираться на подход Serializable в сочетании с настраиваемым поведением сериализации, то мы должны включить эти два метода с такой же точной сигнатурой, что и ниже:

 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 и Custom Serializable кажется справедливым! Результаты могут быть удивительными! Настраиваемый Serializable подход более чем в 3 раза быстрее для записи и в 1,6 раза быстрее для чтения, чем Parcelable.

Отредактировано: -----

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

Для более

Фарханой
источник
@Farhana Как это сделать для класса данных в kotlin?
Nisarg
@ Nisarg Я добавил Kotlin Serialization, посмотрите.
Фархана
@Farhana Это было очень проницательно. Я действительно хочу перейти в kotlin на работе, но мои предложения постоянно отклоняются менеджерами. Мне интересно, смогу ли я получить эталонный тест для Serializable (с пользовательским методом), который, как вы говорите, в 1,6 раза быстрее, чем Parcelable.
Абхинав Кульшрештха
39

Если вы хотите быть хорошим гражданином, уделите дополнительное время внедрению Parcelable, поскольку он будет работать в 10 раз быстрее и потреблять меньше ресурсов.

Однако в большинстве случаев медлительность Serializable не будет заметна. Не стесняйтесь использовать его, но помните, что сериализация - это дорогостоящая операция, поэтому сведите ее к минимуму.

Если вы пытаетесь передать список с тысячами сериализованных объектов, возможно, весь процесс займет больше секунды. Это может сделать переходы или поворот от портрета до пейзажа очень вялыми.

Источник к этому пункту: http://www.developerphil.com/parcelable-vs-serializable/

codercat
источник
32

В Parcelable разработчики пишут собственный код для маршалинга и демаршалинга, поэтому он создает меньше мусорных объектов по сравнению с сериализацией. Благодаря этой пользовательской реализации производительность Parcelable по сравнению с сериализацией значительно улучшается (примерно в два раза быстрее).

Serializable - это маркерный интерфейс, который подразумевает, что пользователь не может упорядочить данные в соответствии со своими требованиями. При сериализации операция маршалинга выполняется на виртуальной машине Java (JVM) с использованием API отражения Java. Это помогает идентифицировать элемент и поведение объекта Java, но также приводит к созданию большого количества мусорных объектов. Из-за этого процесс сериализации идет медленно по сравнению с Parcelable.

Редактировать: Что означает маршаллинг и демаршаллинг?

В нескольких словах, «маршаллинг» относится к процессу преобразования данных или объектов в байтовый поток, а «демаршаллинг» - это обратный процесс преобразования байтового потока в их исходные данные или объект. Преобразование достигается через «сериализацию».

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

Uts
источник
Довольно хорошее объяснение даже без подробного примера. Как раз то, что мне нужно для доработки.
sud007
20

Я на самом деле собираюсь быть тем парнем, который защищает Serializable. Разница в скорости уже не так существенна, поскольку устройства намного лучше, чем несколько лет назад, а также есть и другие, более тонкие различия. Смотрите мой блог на вопрос для получения дополнительной информации.

Неманья Ковачевич
источник
1
Спасибо за акцию. Его менее сложный для реализации сериализуемый и компромисс должен быть решен в тех редких случаях и гипероптимизации.
Анкан-Зероб
2
Альтернативная точка зрения, особенно в сочетании с экспериментами и результатами, очень полезна. Мне приходится работать с большим количеством существующего исходного кода на основе Parcelable, и я могу изменить его часть сейчас, когда я прочитал ваше сообщение в блоге.
Les
14

Parcelable является своего рода стандартом в разработке Android. Но не из-за скорости

Parcelable рекомендуется для передачи данных. Но если вы правильно используете serializable, как показано в этом репозитории , вы увидите, что сериализуемый иногда даже быстрее, чем parcelable. Или, по крайней мере, сроки сопоставимы.

Parcelable быстрее, чем Serializable?

Обычная сериализация Java на среднем устройстве Android (если все сделано правильно *) примерно в 3,6 раза быстрее, чем Parcelable для записи, и примерно в 1,6 раза быстрее для чтения. Также это доказывает, что Java Serialization (если все сделано правильно) - это быстрый механизм хранения, который дает приемлемые результаты даже при относительно больших графах объектов из 11000 объектов с 10 полями в каждом.

* Смысл в том, что обычно каждый, кто слепо заявляет, что «Parcelable намного быстрее», сравнивает его с автоматической сериализацией по умолчанию, которая использует много отражения внутри. Это несправедливое сравнение, потому что Parcelable использует ручную (и очень сложную) процедуру записи данных в поток. Что обычно не упоминается, так это то, что стандартную сериализацию Java в соответствии с документами также можно выполнить вручную, используя методы writeObject () и readObject (). Для получения дополнительной информации см. JavaDocs. Вот как это должно быть сделано для лучшей производительности.

Итак, если сериализуемый процесс быстрее и проще в реализации, почему у Android вообще есть пакет?

Причина в нативном коде. Parcelable создан не только для межпроцессного взаимодействия. Он также может быть использован для связи между кодами . Вы можете отправлять и получать объекты из собственного уровня C ++. Вот и все.

Что выбрать? Оба будут хорошо работать. Но я думаю, что Parcelable - лучший выбор, так как он рекомендован Google, и, как вы можете видеть из этой ветки, он более ценится.

Максим Тураев
источник
Можете ли вы разместить свои источники? Я был бы очень признателен. Спасибо!!
Арчи Г. Киньонес
2
Этот ответ я получил от опытного разработчика, который работает над проектом, связанным с AOSP twitter.com/bwdude . Он сказал, что нативный код C ++ для связи со слоем SDK использует собственную реализацию Parcelable. Я думаю, что он говорит об этом классе android.googlesource.com/platform/frameworks/native/+/… Я знаю, что это не лучшее объяснение, но это лучшее, что у меня есть сейчас. Если вы найдете что-то еще, обязательно разместите это здесь =)
Максим Тураев
Хотелось бы, чтобы я тебя голосовал не раз. Я видел, как отличные эксперты по Android и Java выбирают здесь самый популярный ответ. Отсутствие документации действительно помешало любому вниманию Serializable. Похоже, это эффекты продвижения конкретного API. Спасибо!
pulp_fiction
11

1. Сериализуемый

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

Интерфейс чего?

  • стандартный интерфейс Java

скорость

  • медленнее, чем Parcelable

2. Parcelable

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

Интерфейс чего?

  • это интерфейс android.os
    • это означает, что Google разработал Parcelable для повышения производительности на Android

скорость

  • быстрее (потому что он оптимизирован для использования на разработке Android)

> В заключение

Помните, что Serializable - это стандартный интерфейс Java, а Parcelable - для разработки под Android.

kenju
источник
Вы должны добавить их использование тоже.
Аншул Тяги
7

Существует некоторая проблема производительности, связанная с маршалингом и демаршалингом. Parcelable в два раза быстрее, чем Serializable.

Пожалуйста, перейдите по следующей ссылке:

http://www.3pillarglobal.com/insights/parcelable-vs-java-serialization-in-android-app-development

Тушар Тхакар
источник
Да, вы правы geeksforandroidgeeks.com/android/…
Вивек Кумар Самеле
4

Реализация parcelable может быть быстрее, если вы используете плагин paracelable в Android Studio. поиск Android Генератор парсерабельного кода

Глубокий П
источник
3

Интерфейс Serializable можно использовать так же, как интерфейс Parcelable, что приводит к (не очень) лучшему быстродействию. Просто перезапишите эти два метода для ручного процесса маршалинга и демаршаллинга:

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

Тем не менее, мне кажется, что при разработке нативного Android использование Android API - это путь.

Видеть :

Ceyfiroth
источник
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
    }

}
Kushal
источник
1

Разборчиво гораздо быстрее, чем сериализуемое с помощью Binder, потому что сериализуемое использование отражения и вызывает много GC. Parcelable - это дизайн для оптимизации передачи объекта.

Вот ссылка на ссылку. http://www.developerphil.com/parcelable-vs-serializable/

Хорюн Ли
источник
1

вы можете использовать сериализуемые объекты в намерениях, но во время сериализации объекта Parcelable это может привести к серьезному исключению, например NotSerializableException. Разве не рекомендуется использовать сериализуемый с Parcelable. Поэтому лучше расширить Parcelable объектом, который вы хотите использовать с помощью связки и намерений. Поскольку этот Parcelable специфичен для Android, у него нет побочных эффектов. :)

Рангуш Кумар
источник
0

Сериализуемый

Serializable - это маркируемый интерфейс, или мы можем назвать его пустым интерфейсом. У него нет предварительно реализованных методов. Serializable собирается преобразовать объект в поток байтов. Таким образом, пользователь может передавать данные между одним действием другому. Основное преимущество сериализуемого заключается в том, что создание и передача данных очень просты, но это медленный процесс по сравнению с возможностью их рассылки.

Parcelable

Посылка способна быстрее, чем сериализуемая. Parcel способен конвертировать объект в поток байтов и передавать данные между двумя действиями. Написание кода для посылок немного сложнее по сравнению с сериализацией. Он не создает больше временных объектов при передаче данных между двумя действиями.

Cprk Praveen
источник