Tại sao Android cung cấp 2 giao diện để tuần tự hóa các đối tượng? Các đối tượng Nối tiếp có xen kẽ với Binder
các tệp Android và AIDL không?
Tại sao Android cung cấp 2 giao diện để tuần tự hóa các đối tượng? Các đối tượng Nối tiếp có xen kẽ với Binder
các tệp Android và AIDL không?
Câu trả lời:
Trong Android, chúng ta không thể truyền các đối tượng vào các hoạt động. Để làm điều này, các đối tượng phải thực hiện Serializable
hoặc Parcelable
giao diện.
Nối tiếp
Serializable
là một giao diện Java tiêu chuẩn. Bạn chỉ có thể thực hiện Serializable
giao diện và thêm các phương thức ghi đè. Vấn đề với phương pháp này là sự phản chiếu được sử dụng và nó là một quá trình chậm. Phương pháp này tạo ra rất nhiều đối tượng tạm thời và gây ra khá nhiều bộ sưu tập rác. Tuy nhiên,Serializable
giao diện dễ thực hiện hơn.
Nhìn vào ví dụ dưới đây (Nối tiếp):
// 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");
Bưu kiện
Parcelable
quá trình nhanh hơn nhiều Serializable
. Một trong những lý do cho điều này là chúng tôi đang rõ ràng về quá trình tuần tự hóa thay vì sử dụng sự phản chiếu để suy ra nó. Cũng có lý do rằng mã đã được tối ưu hóa mạnh mẽ cho mục đích này.
Nhìn vào ví dụ dưới đây (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");
Bạn có thể vượt qua ArrayList
các đối tượng Parcelable như dưới đây:
// 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");
Phần kết luận
Parcelable
nhanh hơn Serializable
giao diệnParcelable
Giao diện mất nhiều thời gian hơn để thực hiện so với Serializable
giao diệnSerializable
giao diện dễ thực hiện hơn Serializable
Giao diện tạo ra rất nhiều đối tượng tạm thời và gây ra khá nhiều bộ sưu tập rácParcelable
mảng có thể được truyền qua Intent trong AndroidNối tiếp là một giao diện Java tiêu chuẩn. Bạn chỉ cần đánh dấu một lớp Tuần tự hóa bằng cách triển khai giao diện và Java sẽ tự động tuần tự hóa nó trong các tình huống nhất định.
Bưu kiện là một giao diện cụ thể của Android nơi bạn tự thực hiện việc tuần tự hóa. Nó được tạo ra để có khả năng Nối tiếp hiệu quả hơn nhiều và để giải quyết một số vấn đề với sơ đồ tuần tự hóa Java mặc định.
Tôi tin rằng Binder và AIDL hoạt động với các đối tượng Parcelable.
Tuy nhiên, bạn có thể sử dụng các đối tượng Nối tiếp trong Ý định.
Parcelable vs serializable Tôi giới thiệu hai cái này.
Đối với Java và Kotlin
1) Java
Nối tiếp, đơn giản
Nối tiếp là gì?
Nối tiếp là một giao diện Java tiêu chuẩn. Nó không phải là một phần của SDK Android. Sự đơn giản của nó là vẻ đẹp của nó. Chỉ cần thực hiện giao diện này, POJO của bạn sẽ sẵn sàng để chuyển từ Hoạt động này sang Hoạt động khác.
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;
}
}
Cái hay của serializable là bạn chỉ cần thực hiện giao diện serializable trên một lớp và các con của nó. Nó là một giao diện đánh dấu, có nghĩa là không có phương thức để thực hiện, Java sẽ chỉ đơn giản là nỗ lực hết sức để tuần tự hóa nó một cách hiệu quả.
Vấn đề với phương pháp này là sự phản chiếu được sử dụng và nó là một quá trình chậm. Cơ chế này cũng có xu hướng tạo ra nhiều đối tượng tạm thời và gây ra khá nhiều bộ sưu tập rác.
Tuyệt vời, tốc độ
Parcelable là gì?
Parcelable là một giao diện khác. Mặc dù là đối thủ của nó (Nối tiếp trong trường hợp bạn quên), nó là một phần của SDK Android. Bây giờ, Parcelable được thiết kế đặc biệt theo cách không có sự phản chiếu khi sử dụng nó. Đó là bởi vì chúng tôi đang thực sự rõ ràng cho quá trình tuần tự hóa.
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];
}
};
}
Bây giờ, người chiến thắng là
Kết quả của các thử nghiệm được thực hiện bởi Philippe Breault cho thấy Parcelable nhanh hơn gấp 10 lần so với Nối tiếp. Một số kỹ sư khác của Google cũng đứng sau tuyên bố này.
Theo họ, cách tiếp cận serializable mặc định chậm hơn Parcelable. Và ở đây chúng tôi có một thỏa thuận giữa hai bên! NHƯNG, thật không công bằng khi so sánh hai điều này cả! Bởi vì với Parcelable, chúng tôi thực sự đang viết mã tùy chỉnh. Mã được tạo riêng cho một POJO đó. Do đó, không có rác được tạo ra và kết quả tốt hơn. Nhưng với cách tiếp cận tuần tự hóa mặc định, chúng tôi dựa vào quá trình tuần tự hóa tự động của Java. Quá trình này rõ ràng là không tùy chỉnh và tạo ra rất nhiều rác! Như vậy, kết quả tồi tệ hơn.
Dừng lại !!!!, trước khi đưa ra quyết định
Bây giờ, có một cách tiếp cận khác . Toàn bộ quá trình tự động đằng sau serializable có thể được thay thế bằng mã tùy chỉnh sử dụng các phương thức writeObject () & readObject (). Những phương pháp này là cụ thể. Nếu chúng ta muốn dựa vào cách tiếp cận Nối tiếp kết hợp với hành vi tuần tự hóa tùy chỉnh, thì chúng ta phải bao gồm hai phương thức này có cùng chữ ký chính xác như phương pháp dưới đây:
private void writeObject(java.io.ObjectOutputStream out)
throws IOException;
private void readObject(java.io.ObjectInputStream in)
throws IOException, ClassNotFoundException;
private void readObjectNoData()
throws ObjectStreamException;
Và bây giờ một so sánh giữa Parcelable và serializable tùy chỉnh có vẻ công bằng! Kết quả có thể gây ngạc nhiên! Cách tiếp cận tuần tự hóa tùy chỉnh nhanh hơn gấp 3 lần cho ghi và nhanh hơn 1,6 lần cho đọc so với Parcelable.
Đã chỉnh sửa: -----
2) Tuần tự hóa Kotlinx
Thư viện tuần tự hóa 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
Tập tin của bạn
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'
}
Việc nối tiếp được thực hiện khá dễ dàng, bạn cần chú thích lớp dự định với @Serializable
chú thích như bên dưới
import kotlinx.serialization.Serializable
@Serializable
class Field {
var count: Int = 0
var name: String = ""
}
Hai chú thích nữa cần lưu ý là transient
và optional
. Sử dụng tạm thời sẽ có serializer bỏ qua trường đó và sử dụng tùy chọn sẽ cho phép serializer không bị phá vỡ nếu một trường bị thiếu, nhưng đồng thời sẽ cần phải cung cấp một giá trị mặc định.
@Optional
var isOptional: Boolean = false
@Transient
var isTransient: Boolean = false
Lưu ý : Điều này cũng có thể làm việc với các lớp dữ liệu.
Bây giờ để thực sự sử dụng điều này trong hành động, hãy lấy một ví dụ về cách chuyển đổi JSON thành đối tượng và quay lại
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)
}
Để biết thêm
Serialization
, Có một cái nhìn.
Nếu bạn muốn trở thành một công dân tốt, hãy dành thêm thời gian để triển khai Parcelable vì nó sẽ thực hiện nhanh hơn 10 lần và sử dụng ít tài nguyên hơn.
Tuy nhiên, trong hầu hết các trường hợp, sự chậm chạp của serializable sẽ không được chú ý. Hãy sử dụng nó nhưng hãy nhớ rằng serialization là một hoạt động đắt tiền vì vậy hãy giữ nó ở mức tối thiểu.
Nếu bạn đang cố gắng vượt qua một danh sách với hàng ngàn đối tượng được tuần tự hóa, có thể toàn bộ quá trình sẽ mất hơn một giây. Nó có thể làm cho quá trình chuyển đổi hoặc xoay từ chân dung sang lanscape cảm thấy rất chậm chạp.
Nguồn đến thời điểm này: http://www.developerphil.com/parcelable-vs-serializable/
Trong Parcelable, các nhà phát triển viết mã tùy chỉnh cho việc sắp xếp theo thứ tự và sắp xếp theo thứ tự để nó tạo ra các đối tượng rác ít hơn so với Nối tiếp. Hiệu suất của Parcelable qua serialization cải thiện đáng kể (nhanh hơn khoảng hai lần), do việc triển khai tùy chỉnh này.
Nối tiếp là một giao diện đánh dấu, ngụ ý rằng người dùng không thể sắp xếp dữ liệu theo yêu cầu của họ. Trong Tuần tự hóa, một thao tác sắp xếp được thực hiện trên Máy ảo Java (JVM) bằng API phản chiếu Java. Điều này giúp xác định thành viên và hành vi của đối tượng Java, nhưng cuối cùng cũng tạo ra rất nhiều đối tượng rác. Do đó, quá trình Tuần tự hóa chậm so với Parcelable.
Chỉnh sửa: ý nghĩa của marshalling và unmarshalling là gì?
Nói một cách ngắn gọn, "marshalling" đề cập đến quá trình chuyển đổi dữ liệu hoặc các đối tượng nhập vào luồng byte và "unmarshalling" là quá trình ngược lại để chuyển đổi beack luồng byte sang dữ liệu hoặc đối tượng ban đầu của chúng. Việc chuyển đổi được thực hiện thông qua "tuần tự hóa".
Tôi thực sự sẽ trở thành một người ủng hộ cho serializable. Sự khác biệt về tốc độ không còn quá quyết liệt nữa vì các thiết bị tốt hơn nhiều so với vài năm trước và cũng có những khác biệt khác, tinh tế hơn. Xem bài viết trên blog của tôi về vấn đề này để biết thêm.
Parcelable là phương pháp tiếp cận được khuyến nghị để truyền dữ liệu. Nhưng nếu bạn sử dụng tuần tự hóa một cách chính xác như thể hiện trong repo này , bạn sẽ thấy rằng tuần tự hóa đôi khi còn nhanh hơn sau đó có thể phân lô. Hoặc ít nhất là thời gian là tương đương.
Tuần tự hóa Java thông thường trên một thiết bị Android trung bình (nếu được thực hiện đúng *) nhanh hơn khoảng 3,6 lần so với Parcelable để ghi và nhanh hơn khoảng 1,6 lần cho việc đọc. Ngoài ra, nó chứng minh rằng Tuần tự hóa Java (nếu được thực hiện đúng) là cơ chế lưu trữ nhanh, cho kết quả chấp nhận được ngay cả với các biểu đồ đối tượng tương đối lớn gồm 11000 đối tượng với mỗi trường 10 trường.
* Sidenote thường là tất cả những người mù quáng tuyên bố rằng "Parcelable được kết hợp nhanh hơn" so sánh nó với tuần tự hóa mặc định, sử dụng nhiều sự phản chiếu bên trong. Đây là so sánh không công bằng, bởi vì Parcelable sử dụng thủ tục ghi dữ liệu thủ công (và rất phức tạp) vào luồng. Điều thường không được đề cập là việc tuần tự hóa Java tiêu chuẩn theo các tài liệu cũng có thể được thực hiện theo cách thủ công, sử dụng các phương thức writeObject () và readObject (). Để biết thêm thông tin, xem JavaDocs. Đây là cách nó nên được thực hiện để có hiệu suất tốt nhất.
Lý do là mã nguồn. Parcelable được tạo ra không chỉ dành cho giao tiếp liên tiến trình. Nó cũng có thể được sử dụng để liên lạc mã hóa . Bạn có thể gửi và nhận các đối tượng từ lớp gốc C ++. Đó là nó.
Bạn nên chọn cái gì? Cả hai sẽ làm việc tốt. Nhưng tôi nghĩ rằng Parcelable là sự lựa chọn tốt hơn vì nó được google khuyên dùng và như bạn có thể thấy từ chủ đề này được đánh giá cao hơn nhiều.
@see http://docs.oracle.com/javase/7/docs/api/java/io/Serializable.html
@see http://developer.android.com/reference/android/os/Parcelable.html
Xin lưu ý rằng serializable là giao diện Java tiêu chuẩn và Parcelable dành cho Phát triển Android
Có một số vấn đề về hiệu suất liên quan đến việc sắp xếp và không theo dõi. Parcelable nhanh hơn hai lần so với serializable.
Vui lòng đi qua liên kết sau:
http://www.3pillarglobal.com/insights/parcelable-vs-java-serialization-in-android-app-development
Giao diện serializable có thể được sử dụng giống như giao diện Parcelable, dẫn đến hiệu suất tốt hơn (không nhiều). Chỉ cần ghi đè hai phương thức đó để xử lý quá trình sắp xếp thủ công và không sắp xếp theo thứ tự:
private void writeObject(java.io.ObjectOutputStream out)
throws IOException
private void readObject(java.io.ObjectInputStream in)
throws IOException, ClassNotFoundException
Tuy nhiên, dường như đối với tôi, khi phát triển Android gốc, sử dụng api Android là cách tốt nhất.
Xem :
Tôi trả lời trễ, nhưng đăng với hy vọng rằng nó sẽ giúp người khác.
Về tốc độ , Parcelable > Serializable
. Nhưng, Custom serializable là ngoại lệ. Nó gần như nằm trong phạm vi của Parcelable hoặc thậm chí nhanh hơn.
Tham khảo: https://www.geekforgeek.org/customized-serialization-and-deserialization-in-java/
Thí dụ :
Lớp tùy chỉnh được đăng
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
}
}
Parcelable nhanh hơn nhiều so với tuần tự hóa với Binder, bởi vì tuần tự hóa sử dụng phản xạ và gây ra nhiều GC. Parcelable là thiết kế để tối ưu hóa để vượt qua đối tượng.
Đây là liên kết để tham khảo. http://www.developerphil.com/parcelable-vs-serializable/
bạn có thể sử dụng các đối tượng tuần tự hóa trong các ý định nhưng tại thời điểm thực hiện tuần tự hóa một đối tượng Parcelable, nó có thể đưa ra một ngoại lệ nghiêm trọng như NotSerializableException. Có phải nó không được khuyến khích sử dụng serializable với Parcelable. Vì vậy, tốt hơn là mở rộng Parcelable với đối tượng mà bạn muốn sử dụng với gói và ý định. Vì Parcelable này là dành riêng cho Android nên nó không có bất kỳ tác dụng phụ nào. :)
Nối tiếp
Nối tiếp là một giao diện có thể đánh dấu hoặc chúng ta có thể gọi là một giao diện trống. Nó không có bất kỳ phương pháp được thực hiện trước. Nối tiếp sẽ chuyển đổi một đối tượng thành luồng byte. Vì vậy, người dùng có thể chuyển dữ liệu giữa một hoạt động này sang hoạt động khác. Ưu điểm chính của tuần tự hóa là việc tạo và truyền dữ liệu rất dễ dàng nhưng nó là một quá trình chậm so với phân phối.
Bưu kiện
Parcel có khả năng nhanh hơn tuần tự hóa. Parcel có khả năng sẽ chuyển đổi đối tượng thành luồng byte và truyền dữ liệu giữa hai hoạt động. Viết mã bưu kiện có thể hơi phức tạp một chút so với tuần tự hóa. Nó không tạo ra nhiều đối tượng tạm thời trong khi truyền dữ liệu giữa hai hoạt động.