Android: differenza tra parcelable e serializzabile?


313

Perché Android fornisce 2 interfacce per serializzare gli oggetti? Gli oggetti serializzabili interagiscono con i Binderfile Android e AIDL?

Risposte:


444

In Android non possiamo semplicemente passare oggetti alle attività. Per fare ciò, gli oggetti devono implementare Serializableo Parcelableinterfacciarsi.

Serializable

Serializableè un'interfaccia Java standard. Puoi semplicemente implementare l' Serializableinterfaccia e aggiungere metodi di sostituzione. Il problema con questo approccio è che viene utilizzata la riflessione ed è un processo lento. Questo metodo crea molti oggetti temporanei e provoca un bel po 'di garbage collection. Però,Serializable interfaccia è più facile da implementare.

Guarda l'esempio seguente (serializzabile):

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

Impacchettabile

Parcelableil processo è molto più veloce di Serializable. Uno dei motivi di ciò è che siamo espliciti sul processo di serializzazione invece di usare la riflessione per inferirlo. È anche ovvio che il codice è stato fortemente ottimizzato per questo scopo.

Guarda l'esempio seguente (parcelabile):

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

Puoi passare ArrayListoggetti Parcelable come di seguito:

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

Conclusione

  1. Parcelableè più veloce Serializabledell'interfaccia
  2. Parcelablel'interfaccia richiede più tempo per l'implementazione rispetto Serializableall'interfaccia
  3. Serializable l'interfaccia è più facile da implementare
  4. Serializable L'interfaccia crea molti oggetti temporanei e provoca un bel po 'di garbage collection
  5. Parcelable l'array può essere passato tramite Intent in Android

2
@Sujith cosa intendi per riflessione è usato ? Che cos'è la riflessione ?
AnV

11
@AbhinavVutukuri Reflection è il termine per ispezionare oggetti, campi e metodi in fase di esecuzione tramite Object.getClass () e simili.
FaultException

2
I serializzabili sono migliori per i dati persistenti, d'altra parte gli oggetti parcellabili non dovrebbero essere affatto persistenti. È davvero una brutta pratica
TheAnimatrix

2
@Sujith Come più di una persona ha affermato, gli oggetti parcelabili non possono essere persistenti (in modo affidabile) ma quelli serializzabili (entro certi limiti). Poiché la tua risposta è il punteggio più alto e dà l'impressione di coprire tutte le differenze importanti, dovresti probabilmente menzionare questo punto.
LarsH,

4
Ora l'implementazione di Parcelable è veloce quanto Serializable, basta premere ALT + INSERT su qualsiasi classe che implementa Parcelable in Android Studio e l'IDE lo farà.
Ali Nem,

183

Serializable è un'interfaccia Java standard. È sufficiente contrassegnare una classe serializzabile implementando l'interfaccia e Java lo serializzerà automaticamente in determinate situazioni.

Parcelable è un'interfaccia specifica per Android in cui implementi tu stesso la serializzazione. È stato creato per essere molto più efficiente di Serializable e per aggirare alcuni problemi con lo schema di serializzazione Java predefinito.

Credo che Binder e AIDL funzionino con oggetti Parcelable.

Tuttavia, è possibile utilizzare oggetti serializzabili in Intenti.


1
come posso serializzare un oggetto parcelable? Come posso renderlo persistente?
Ade,

@Haded Ottieni il contenuto dello stato degli oggetti e memorizzalo in un file o in un database SQLLite. La serializzazione è utile per rendere gli oggetti trasferibili tra diversi componenti in Android o in diverse applicazioni.
Jonathan,

6
Questa è un'ottima spiegazione Ho anche notato questo: "Il pacco non è un meccanismo di serializzazione per scopi generici. Questa classe (e la corrispondente API parcelabile per posizionare oggetti arbitrari in un pacco) è progettata come un trasporto IPC ad alte prestazioni. Pertanto, non è appropriato collocare tutti i dati dei pacchi nell'archiviazione persistente: i cambiamenti nell'implementazione sottostante di tutti i dati nel pacco possono rendere illeggibili i dati più vecchi. " developer.android.com/reference/android/os/Parcel.html
Sam003

@Zhisheng cosa si intende per oggetti arbitrari? che tipo di oggetti possiamo mettere nel pacco?
hasnain_ahmad,

Che ne dici di convertire oggetti in stringa json invece con gson?
FOO,

57

Parcelable vs Serializable Mi riferisco a questi due.

Per Java e Kotlin

1) Java

Serializable, la semplicità

Cosa è serializzabile?

Serializable è un'interfaccia Java standard. Non fa parte dell'SDK di Android. La sua semplicità è la sua bellezza. Semplicemente implementando questa interfaccia il tuo POJO sarà pronto per passare da un'attività all'altra.

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;
}
}
  • Il vantaggio di serializzare è che devi solo implementare l'interfaccia Serializable su una classe e sui suoi figli. È un'interfaccia marcatore, il che significa che non esiste un metodo da implementare, Java farà semplicemente del suo meglio per serializzare in modo efficiente.

  • Il problema con questo approccio è che viene utilizzata la riflessione ed è un processo lento. Questo meccanismo tende anche a creare molti oggetti temporanei e causare un bel po 'di garbage collection.

Parcelable, The Speed

Cos'è Parcelable?

Parcelable è un'altra interfaccia. Nonostante il suo rivale (serializzabile nel caso in cui ti fossi dimenticato), fa parte dell'SDK di Android. Ora, Parcelable è stato specificamente progettato in modo tale da non riflettere sull'uso. Questo perché siamo veramente espliciti per il processo di serializzazione.

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];
    }
};
}

Ora, il vincitore è

inserisci qui la descrizione dell'immagine

I risultati dei test condotti da Philippe Breault mostrano che Parcelable è più di 10 volte più veloce di Serializable. Anche alcuni altri ingegneri di Google sostengono questa affermazione.

Secondo loro, l'approccio serializzabile predefinito è più lento di Parcelable. E qui abbiamo un accordo tra le due parti! MA, non è giusto confrontare questi due! Perché con Parcelable stiamo effettivamente scrivendo codice personalizzato. Codice creato appositamente per quel POJO. Pertanto, non viene creata immondizia e i risultati sono migliori. Ma con l'approccio serializzabile predefinito, facciamo affidamento sul processo di serializzazione automatica di Java. Apparentemente il processo non è affatto personalizzato e crea molta spazzatura! Pertanto, i risultati peggiori.

Stop Stop !!!!, prima di prendere una decisione

Ora c'è un altro approccio . L'intero processo automatico dietro Serializable può essere sostituito dal codice personalizzato che utilizza i metodi writeObject () e readObject (). Questi metodi sono specifici. Se vogliamo fare affidamento sull'approccio serializzabile in combinazione con il comportamento di serializzazione personalizzato, dobbiamo includere questi due metodi con la stessa firma esatta di quello seguente:

 private void writeObject(java.io.ObjectOutputStream out)
 throws IOException;

 private void readObject(java.io.ObjectInputStream in)
     throws IOException, ClassNotFoundException;

 private void readObjectNoData()
     throws ObjectStreamException;

E ora un confronto tra Parcelable e Serializable personalizzato sembra giusto! I risultati potrebbero essere sorprendenti! L'approccio serializzabile personalizzato è oltre 3 volte più veloce per le scritture e 1,6 volte più veloce per le letture rispetto a Parcelable.

Modificato:-----

2) Serializzazione di Kotlinx

Kotlinx serializzazione Biblioteca

For Kotlin serialization need to add below dependency and plugin

implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime:0.9.1"

apply plugin: 'kotlinx-serialization'

Il tuo build.gradlefile

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

La serializzazione viene eseguita abbastanza facilmente, è necessario annotare la classe desiderata con l' @Serializableannotazione come di seguito

import kotlinx.serialization.Serializable
@Serializable
class Field {
    var count: Int = 0
    var name: String = ""
}

Altre due annotazioni da notare sono transiente optional. L'uso del transiente farà sì che il serializzatore ignori quel campo e l'uso di facoltativo consentirà al serializzatore di non rompersi se manca un campo, ma allo stesso tempo sarà necessario fornire un valore predefinito.

@Optional
var isOptional: Boolean = false
@Transient
var isTransient: Boolean = false

Nota : questo può funzionare anche con le classi di dati.

Ora per usarlo effettivamente in azione facciamo un esempio di come convertire un JSON in oggetto e viceversa

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

Per di più


@Farhana Come si fa per la classe di dati in kotlin?
Nisarg,

@Nisarg ho aggiunto Kotlin Serialization, dai un'occhiata.
Farhana,

@Farhana Questo è stato molto penetrante. Voglio davvero passare al kotlin al lavoro, ma la mia proposta viene costantemente respinta dai manager. Mi chiedo se posso ottenere benchmark per Serializable (con metodo personalizzato) che dici 1,6 volte più veloce di Parcelable.
Abhinav Kulshreshtha,

39

Se vuoi essere un buon cittadino, prenditi il ​​tempo extra per implementare Parcelable dal momento che funzionerà 10 volte più velocemente e utilizzerà meno risorse.

Tuttavia, nella maggior parte dei casi, la lentezza di Serializable non sarà evidente. Sentiti libero di usarlo, ma ricorda che la serializzazione è un'operazione costosa, quindi tienila al minimo.

Se si sta tentando di passare un elenco con migliaia di oggetti serializzati, è possibile che l'intero processo richiederà più di un secondo. Può rendere molto lente le transizioni o la rotazione dal ritratto al paesaggio.

Fonte a questo punto: http://www.developerphil.com/parcelable-vs-serializable/


32

In Parcelable, gli sviluppatori scrivono codice personalizzato per il marshalling e il unmarshaling in modo da creare meno oggetti spazzatura rispetto alla serializzazione. Le prestazioni di Parcelable over Serialization migliorano notevolmente (circa due volte più velocemente), grazie a questa implementazione personalizzata.

Serializable è un'interfaccia marker, che implica che l'utente non può eseguire il marshalling dei dati in base alle proprie esigenze. Nella serializzazione, un'operazione di marshalling viene eseguita su una Java Virtual Machine (JVM) utilizzando l'API di riflessione Java. Questo aiuta a identificare il membro e il comportamento dell'oggetto Java, ma finisce anche per creare molti oggetti spazzatura. Per questo motivo, il processo di serializzazione è lento rispetto a Parcelable.

Modifica: Qual è il significato di marshalling e unmarshalling?

In poche parole, "marshalling" si riferisce al processo di conversione dei dati o degli oggetti in un flusso di byte e "unmarshalling" è il processo inverso di conversione del beack del flusso di byte nei loro dati o oggetti originali. La conversione avviene tramite "serializzazione".

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


Spiegazione abbastanza buona anche senza un esempio dettagliato. Proprio quello di cui avevo bisogno per la revisione.
sud007,

20

In realtà sarò l'unico a sostenere il serializzabile. La differenza di velocità non è più così drastica poiché i dispositivi sono molto migliori rispetto a diversi anni fa e ci sono anche altre differenze più sottili. Vedi il mio post sul blog sul problema per maggiori informazioni.


1
Grazie per la condivisione. È meno complesso da implementare serializzabile e il compromesso deve essere deciso in quei casi rari e iper ottimizzati.
Ankan-Zerob,

2
Il punto di vista alternativo, specialmente se supportato da esperimenti e risultati, è molto utile. Devo lavorare con un sacco di codice sorgente basato su Parcelable esistente e potrei rifattorarne alcuni ora che ho letto il tuo post sul blog.
Les

14

Parcelable è una specie di standard nello sviluppo di Android. Ma non per la velocità

Parcelable è l'approccio raccomandato per i trasferimenti di dati. Ma se si utilizza serializzabile correttamente come mostrato in questo repository , vedrai che la serializzazione a volte è anche più veloce del pacchetto. O almeno i tempi sono comparabili.

Parcelable è più veloce di Serializable?

La normale serializzazione Java su un dispositivo Android medio (se eseguita correttamente *) è circa 3,6 volte più veloce di Parcelable per le scritture e circa 1,6 volte più veloce per le letture. Inoltre dimostra che la serializzazione Java (se eseguita correttamente) è un meccanismo di archiviazione veloce che fornisce risultati accettabili anche con grafici di oggetti relativamente grandi di 11000 oggetti con 10 campi ciascuno.

* Il sidenote è che di solito tutti coloro che affermano ciecamente che "Parcelable is push fast" lo confronta con la serializzazione automatica predefinita, che utilizza molta riflessione all'interno. Questo è un confronto ingiusto, perché Parcelable utilizza una procedura manuale (e molto complicata) per scrivere i dati nel flusso. Ciò che di solito non viene menzionato è che lo standard serializzabile Java secondo i documenti può anche essere fatto in modo manuale, usando i metodi writeObject () e readObject (). Per maggiori informazioni vedi JavaDocs. Ecco come dovrebbe essere fatto per le migliori prestazioni.

Quindi, se la serializzazione è più veloce e più facile da implementare, perché Android ha parcelable a tutti?

Il motivo è il codice nativo. Il pacchetto non viene creato solo per la comunicazione tra processi. Può anche essere usato per la comunicazione intercodale . È possibile inviare e ricevere oggetti dal livello nativo C ++. Questo è tutto.

Cosa dovresti scegliere? Entrambi funzioneranno bene. Ma penso che Parcelable sia la scelta migliore poiché è consigliato da Google e come puoi vedere da questa discussione è molto più apprezzato.


Puoi collocare le tue fonti? Lo apprezzerei molto. Grazie!!
Archie G. Quiñones,

2
Questa risposta è stata ottenuta da uno sviluppatore esperto che lavora al progetto relativo ad AOSP twitter.com/bwdude . Ha detto che il codice C ++ nativo per la comunicazione con il livello SDK utilizza la propria implementazione di Parcelable. Immagino che parli di questa classe android.googlesource.com/platform/frameworks/native/+/… So che questa non è la migliore spiegazione, ma è la migliore che ho in questo momento. Se troverai qualcos'altro, assicurati di pubblicarlo qui =)
Maksim Turaev

Vorrei poterti votare più di una volta. Ho visto grandi esperti di Android e Java cercare la risposta più votata qui. La mancanza di documentazione ha davvero impedito qualsiasi ribalta per Serializable. Sembra che questi siano effetti della promozione di un'API specifica. Grazie!
pulp_fiction,

11

1. Serializzabile

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

Interfaccia di cosa?

  • è un'interfaccia Java standard

Velocità

  • più lento di Parcelable

2. Parcelable

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

Interfaccia di cosa?

  • è l'interfaccia android.os
    • il che significa che Google ha sviluppato Parcelable per prestazioni migliori su Android

Velocità

  • più veloce (perché è ottimizzato per l'utilizzo sullo sviluppo Android)

> In conclusione

Tieni presente che Serializable è un'interfaccia Java standard e Parcelable è per lo sviluppo Android


Dovresti aggiungere anche gli usi di essi.
Anshul Tyagi,


4

L'implementazione del pacchetto può essere più veloce se usi un plug-in paracelable in Android Studio. cerca il generatore di codice parcelable per Android


3

L'interfaccia serializzabile può essere utilizzata allo stesso modo di Parcelable, ottenendo prestazioni (non molto) migliori. Basta sovrascrivere questi due metodi per gestire il marshalling manuale e il processo di smarsing:

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

Tuttavia, mi sembra che quando si sviluppa Android nativo, utilizzare l'API Android è la strada da percorrere.

Vedi:


2

Sono in ritardo nella risposta, ma invio con la speranza che possa aiutare gli altri.

In termini di velocità , Parcelable > Serializable. Ma la serializzazione personalizzata è un'eccezione. È quasi nel raggio di Parcelable o anche più veloce.

Riferimento: https://www.geeksforgeeks.org/customized-serialization-and-deserialization-in-java/

Esempio :

Classe personalizzata da serializzare

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

puoi usare gli oggetti serializzabili negli intenti ma al momento della serializzazione di un oggetto Parcelable può dare una grave eccezione come NotSerializableException. Non è consigliabile utilizzare serializzabile con Parcelable. Quindi è meglio estendere Parcelable con l'oggetto che si desidera utilizzare con bundle e intenti. Poiché questo Parcelable è specifico per Android, non ha effetti collaterali. :)


0

Serializable

Serializable è un'interfaccia contrassegnabile o possiamo chiamare come un'interfaccia vuota. Non ha metodi pre-implementati. Serializable sta per convertire un oggetto in un flusso di byte. Quindi l'utente può passare i dati tra un'attività a un'altra attività. Il vantaggio principale della serializzazione è la creazione e il passaggio dei dati è molto semplice, ma è un processo lento rispetto al pacchetto.

Impacchettabile

Il pacco è più veloce di serializzabile. Il pacchetto in grado di convertire l'oggetto in un flusso di byte e passare i dati tra due attività. La scrittura di codice pacchi è un po 'complessa rispetto alla serializzazione. Non crea più oggetti temporanei mentre passa i dati tra due attività.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.