Dlaczego Android zapewnia 2 interfejsy do serializacji obiektów? Czy obiekty Binder
nadające się do serializacji współpracują z plikami Androida i AIDL?
Dlaczego Android zapewnia 2 interfejsy do serializacji obiektów? Czy obiekty Binder
nadające się do serializacji współpracują z plikami Androida i AIDL?
Odpowiedzi:
W Androidzie nie możemy po prostu przekazywać obiektów do działań. Aby to zrobić, obiekty muszą zostać zaimplementowane Serializable
lub Parcelable
interfejs.
Serializowalny
Serializable
to standardowy interfejs Java. Możesz po prostu zaimplementować Serializable
interfejs i dodać metody zastępowania. Problem z tym podejściem polega na tym, że stosuje się refleksję i jest to proces powolny. Ta metoda tworzy wiele tymczasowych obiektów i powoduje sporo śmiecia. Jednak Serializable
interfejs jest łatwiejszy do wdrożenia.
Spójrz na poniższy przykład (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");
Paczka
Parcelable
proces jest znacznie szybszy niż Serializable
. Jednym z powodów tego jest to, że mówimy wprost o procesie serializacji zamiast używać refleksji do wnioskowania. Ma również uzasadnienie, że kod został mocno zoptymalizowany do tego celu.
Spójrz na poniższy przykład (działki):
// 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");
Możesz przekazać ArrayList
obiekty do paczkowania, jak poniżej:
// 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");
Wniosek
Parcelable
jest szybszy niż Serializable
interfejsParcelable
Interfejs wymaga więcej czasu na wdrożenie niż Serializable
interfejsSerializable
interfejs jest łatwiejszy do wdrożenia Serializable
Interfejs tworzy wiele tymczasowych obiektów i powoduje sporo śmieciaParcelable
tablica może być przekazywana przez Intent w AndroidzieSerializable to standardowy interfejs Java. Po prostu zaznaczasz klasę Serializable, implementując interfejs, a Java automatycznie serializuje ją w określonych sytuacjach.
Parcelable to interfejs specyficzny dla Androida, w którym samodzielnie wdrażasz serializację. Został stworzony, aby być znacznie bardziej wydajnym niż Serializable i ominąć niektóre problemy z domyślnym schematem serializacji Java.
Uważam, że Binder i AIDL współpracują z obiektami paczkowalnymi.
Jednak można używać obiektów Serializowalnych w Intentach.
Paczkowany vs Serializowalny Odnoszę te dwa.
Dla Javy i Kotlin
1) Java
Serializowalny, prostota
Co to jest Serializowalny?
Serializable to standardowy interfejs Java. Nie jest częścią zestawu Android SDK. Jego prostota to piękno. Po wdrożeniu tego interfejsu Twoje POJO będzie gotowe do przejścia z jednej Aktywności do drugiej.
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;
}
}
Zaletą serializacji jest to, że wystarczy zaimplementować interfejs Serializable na klasie i jej dzieciach. Jest to interfejs znaczników, co oznacza, że nie ma metody implementacji, Java po prostu dołoży wszelkich starań, aby skutecznie serializować go.
Problem z tym podejściem polega na tym, że stosuje się refleksję i jest to proces powolny. Mechanizm ten ma również tendencję do tworzenia wielu tymczasowych obiektów i powodowania sporo śmieci.
Przesyłki, prędkość
Co to jest paczka?
Parcelable to kolejny interfejs. Pomimo rywalizacji (Serializable, jeśli zapomniałeś), jest częścią zestawu Android SDK. Teraz Parcelable został specjalnie zaprojektowany w taki sposób, aby podczas użytkowania nie było odbicia. Wynika to z tego, że jesteśmy bardzo szczerzy w procesie serializacji.
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];
}
};
}
Teraz zwycięzcą jest
Wyniki testów przeprowadzonych przez Philippe'a Breaulta pokazują, że paczka jest ponad 10 razy szybsza niż Serializable. Za tym stwierdzeniem stoją także inni inżynierowie Google.
Według nich domyślne podejście Serializowalne jest wolniejsze niż działki paczkowane. I tutaj mamy porozumienie między obiema stronami! ALE, porównywanie tych dwóch jest niesprawiedliwe! Ponieważ w Parcelable piszemy niestandardowy kod. Kod stworzony specjalnie dla tego jednego POJO. W ten sposób nie są tworzone śmieci, a wyniki są lepsze. Ale przy domyślnym podejściu Serializowalnym polegamy na automatycznym procesie serializacji Java. Proces ten najwyraźniej wcale nie jest niestandardowy i powoduje mnóstwo śmieci! Zatem gorsze wyniki.
Stop Stop !!!!, przed podjęciem decyzji
Teraz jest inne podejście . Cały automatyczny proces Serializable można zastąpić niestandardowym kodem, który wykorzystuje metody writeObject () i readObject (). Te metody są specyficzne. Jeśli chcemy polegać na podejściu Serializable w połączeniu z niestandardowym zachowaniem serializacji, musimy uwzględnić te dwie metody z taką samą dokładną sygnaturą, jak poniżej:
private void writeObject(java.io.ObjectOutputStream out)
throws IOException;
private void readObject(java.io.ObjectInputStream in)
throws IOException, ClassNotFoundException;
private void readObjectNoData()
throws ObjectStreamException;
A teraz porównanie między Paczkową a niestandardową Serializowalną wydaje się uczciwe! Wyniki mogą być zaskakujące! Niestandardowe podejście do szeregowania jest ponad 3-krotnie szybsze w przypadku zapisów i 1,6 razy szybsze w przypadku odczytów niż w przypadku paczek.
Edytowano: -----
2) Serializacja Kotlinx
Biblioteka Serialization 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'
Twój build.gradle
plik
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'
}
Serializacja odbywa się dość łatwo, należy opisać klasę przeznaczoną do niej @Serializable
adnotacją jak poniżej
import kotlinx.serialization.Serializable
@Serializable
class Field {
var count: Int = 0
var name: String = ""
}
Dwie dodatkowe adnotacje do odnotowania to transient
i optional
. Użycie przejściowego spowoduje, że serializator zignoruje to pole, a użycie opcjonalnego pozwoli serializatorowi nie pęknąć, jeśli brakuje pola, ale jednocześnie należy podać wartość domyślną.
@Optional
var isOptional: Boolean = false
@Transient
var isTransient: Boolean = false
Uwaga : Może to również działać z klasami danych.
Teraz, aby faktycznie użyć tego w działaniu, weźmy przykład konwersji JSON na obiekt i odwrotnie
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)
}
Po więcej
Serialization
, zobacz.
Jeśli chcesz być dobrym obywatelem, poświęć dodatkowy czas na wdrożenie paczkowania, ponieważ będzie działać 10 razy szybciej i zużyje mniej zasobów.
Jednak w większości przypadków spowolnienie Serializable nie będzie zauważalne. Możesz go używać, ale pamiętaj, że serializacja jest kosztowną operacją, więc ogranicz ją do minimum.
Jeśli próbujesz przekazać listę z tysiącami serializowanych obiektów, możliwe, że cały proces zajmie więcej niż sekundę. Może sprawić, że przejścia lub obrót z portretu do krajobrazu będą bardzo powolne.
Źródło do tego punktu: http://www.developerphil.com/parcelable-vs-serializable/
W Parcelable programiści piszą niestandardowy kod do zestawiania i rozpakowywania, dzięki czemu tworzy mniej obiektów śmieciowych w porównaniu do serializacji. Wydajność paczki nad serializacją znacznie się poprawia (około dwa razy szybciej) z powodu tej niestandardowej implementacji.
Serializable to interfejs znaczników, co oznacza, że użytkownik nie może gromadzić danych zgodnie z ich wymaganiami. W serializacji operacja zestawiania jest wykonywana na wirtualnej maszynie Java (JVM) przy użyciu interfejsu API refleksji Java. Pomaga to zidentyfikować element członkowski i zachowanie obiektu Java, ale także powoduje powstanie wielu śmieci. Z tego powodu proces serializacji jest powolny w porównaniu do paczkowanego.
Edycja: Jakie znaczenie ma rozebranie i rozebranie?
W kilku słowach „marshalling” odnosi się do procesu konwersji danych lub obiektów w strumień bajtów, a „unmarshalling” jest odwrotnym procesem konwersji beack strumienia bajtów na ich oryginalne dane lub obiekt. Konwersja odbywa się poprzez „serializację”.
Właściwie to będę jedyną osobą, która będzie promować Serializable. Różnica prędkości nie jest już tak drastyczna, ponieważ urządzenia są znacznie lepsze niż kilka lat temu, a także istnieją inne, bardziej subtelne różnice. Aby uzyskać więcej informacji, zobacz mój blog na ten temat.
Przesyłki zalecane są do przesyłania danych. Ale jeśli użyjesz serializowalnego poprawnie, jak pokazano w tym repozytorium , zobaczysz, że serializowalność jest czasem nawet szybsza niż pakowalna. Lub przynajmniej czasy są porównywalne.
Zwykła serializacja Java na przeciętnym urządzeniu z Androidem (jeśli jest wykonana poprawnie *) jest około 3,6 razy szybsza niż Parcelable dla zapisów i około 1,6 razy szybsza dla odczytów. Dowodzi to również, że serializacja Java (jeśli jest wykonana poprawnie) jest szybkim mechanizmem przechowywania, który daje akceptowalne wyniki nawet przy stosunkowo dużych wykresach obiektowych 11000 obiektów z 10 polami każdy.
* Teza jest taka, że zwykle każdy, kto ślepo stwierdza, że „paczka jest szybsza” porównuje ją do domyślnej automatycznej serializacji, która wykorzystuje dużo refleksji wewnątrz. Jest to niesprawiedliwe porównanie, ponieważ Parcelable korzysta z ręcznej (i bardzo skomplikowanej) procedury zapisywania danych do strumienia. Zazwyczaj nie wspomina się o tym, że standardowy Java Serializable zgodnie z dokumentami można również wykonać ręcznie, używając metod writeObject () i readObject (). Aby uzyskać więcej informacji, zobacz JavaDocs. Tak należy zrobić, aby uzyskać najlepszą wydajność.
Powodem jest kod macierzysty. Paczka jest tworzona nie tylko do komunikacji międzyprocesowej. Może być również używany do komunikacji między kodami . Możesz wysyłać i odbierać obiekty z macierzystej warstwy C ++. Otóż to.
Co wybrać Oba będą działać dobrze. Ale myślę, że Parcelable jest lepszym wyborem, ponieważ jest polecany przez Google i jak widać z tego wątku, jest o wiele bardziej doceniany.
@ patrz http://docs.oracle.com/javase/7/docs/api/java/io/Serializable.html
@ patrz http://developer.android.com/reference/android/os/Parcelable.html
Należy pamiętać, że Serializable to standardowy interfejs Java, a Parcelable jest przeznaczony do programowania na Androida
Występuje pewien problem z wydajnością w odniesieniu do zestawiania i rozpakowywania. Paczkowany jest dwa razy szybszy niż Serializowalny.
Proszę przejść przez następujący link:
http://www.3pillarglobal.com/insights/parcelable-vs-java-serialization-in-android-app-development
Wdrożenie paczki może być szybsze, jeśli użyjesz wtyczki Paracelable w Android Studio. wyszukaj generator kodu działki na Androida
Interfejs Serializable może być używany w ten sam sposób, co interfejs Parcelable, co daje (niewiele) lepsze wyniki. Wystarczy zastąpić te dwie metody obsługi ręcznego zestawiania i rozpakowywania:
private void writeObject(java.io.ObjectOutputStream out)
throws IOException
private void readObject(java.io.ObjectInputStream in)
throws IOException, ClassNotFoundException
Wydaje mi się jednak, że przy opracowywaniu natywnego Androida, najlepszym rozwiązaniem jest użycie interfejsu API Androida.
Widzieć :
Spóźniam się z odpowiedzią, ale piszę z nadzieją, że pomoże to innym.
Jeśli chodzi o szybkość , Parcelable > Serializable
. Ale niestandardowe serializowanie jest wyjątkiem. Jest prawie w zasięgu paczki lub nawet szybciej.
Odniesienie: https://www.geeksforgeeks.org/customized-serialization-and-deserialization-in-java/
Przykład:
Klasa niestandardowa do serializacji
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
}
}
Paczka jest znacznie szybsza niż serializowana z Binder, ponieważ serializowalne użycie odbicia i powoduje wiele GC. Parcelable to konstrukcja zoptymalizowana pod kątem przekazywania obiektu.
Oto link do referencji. http://www.developerphil.com/parcelable-vs-serializable/
możesz użyć obiektów możliwych do serializacji w zamierzeniu, ale w momencie serializacji obiektu Parcelable może dać poważny wyjątek, taki jak NotSerializableException. Czy nie jest zalecane używanie serializowalnego z paczkowanym. Dlatego lepiej jest rozszerzyć działkę paczkową o obiekt, którego chcesz użyć z pakietem i zamiarami. Ponieważ ten działka jest specyficzny dla Androida, więc nie ma żadnych skutków ubocznych. :)
Serializowalny
Serializable to interfejs oznaczalny lub możemy go wywołać jako pusty interfejs. Nie ma żadnych wcześniej zaimplementowanych metod. Serializable zamierza przekonwertować obiekt na strumień bajtów. Użytkownik może więc przekazywać dane między jednym działaniem a drugim. Główną zaletą serializacji jest tworzenie i przekazywanie danych jest bardzo łatwe, ale jest to proces powolny w porównaniu do paczkowania.
Paczka
Usługa paczkowania jest szybsza niż możliwość serializacji. Działka paczkowa zamierza przekonwertować obiekt na strumień bajtów i przekazać dane między dwoma działaniami. Pisanie paczkowego kodu jest trochę skomplikowane w porównaniu do serializacji. Nie tworzy więcej obiektów tymczasowych podczas przekazywania danych między dwoma działaniami.