Triển khai Serializable cho Custom Object
Serializable là marker interface trong Java (java.io.Serializable). Chỉ cần implements Serializable để object có thể chuyển thành byte stream để truyền qua Intent, Bundle, lưu file, network...
Bước 1: Tạo dự án mới
Khởi tạo project Android Studio.
Bước 3: Model Class Serializable (src/SerializableObject.java)
package com.example.myapplication;
import java.io.Serializable;
public class SerializableObject implements Serializable {
// Khuyến nghị: serialVersionUID để kiểm soát version
private static final long serialVersionUID = 1L;
private String name;
private int age;
private transient String password; // transient = KHÔNG serialize field này
public SerializableObject(String name, int age, String password) {
this.name = name;
this.age = age;
this.password = password;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
// password không được serialize do transient
public String getPassword() {
return password;
}
@Override
public String toString() {
return "SerializableObject{name='" + name + "', age=" + age + "}";
}
}
Bước 2: Layout (res/layout/activity_main.xml)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:tools="https://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
tools:context=".MainActivity">
<Button
android:id="@+id/btnSerializable"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Tạo & Truyền Serializable Object"
android:padding="16dp" />
</LinearLayout>
Bước 3: MainActivity.java - Truyền qua Intent
package com.example.myapplication;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.RequiresApi;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.btnSerializable).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// Tạo object
SerializableObject user = new SerializableObject("Sairam Krishna", 25, "secret123");
// Truyền qua Intent sang Activity khác
Intent intent = new Intent(MainActivity.this, DetailActivity.class);
intent.putExtra("user_object", user); // Serializable object
startActivity(intent);
Toast.makeText(MainActivity.this, "Đã gửi: " + user.getName(), Toast.LENGTH_SHORT).show();
}
});
}
}
Bước 4: DetailActivity.java - Nhận object
package com.example.myapplication;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;
public class DetailActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_detail);
// Nhận Serializable object từ Intent
SerializableObject user = (SerializableObject) getIntent().getSerializableExtra("user_object");
TextView tvInfo = findViewById(R.id.tvInfo);
if (user != null) {
tvInfo.setText("Nhận được:\n" + user.toString() + "\nPassword: " + user.getPassword()); // Password sẽ null
} else {
tvInfo.setText("Không nhận được object");
}
}
}
Layout Detail (res/layout/activity_detail.xml)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:padding="24dp">
<TextView
android:id="@+id/tvInfo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="18sp"
android:gravity="center" />
</LinearLayout>
Manifest - Đăng ký DetailActivity
<activity android:name=".DetailActivity" />
Các điểm quan trọng về Serializable
1. serialVersionUID
private static final long serialVersionUID = 1L;
- Nếu không khai báo, JVM tự tính dựa trên cấu trúc class
- Khi thay đổi class (thêm/bớt field), UID thay đổi →
InvalidClassExceptionkhi deserialize - Luôn khai báo explicit để kiểm soát version
2. transient keyword
private transient String password; // Không serialize
- Field marked transient sẽ bị bỏ qua khi serialize
- Giá trị sẽ là null (object) hoặc default value (primitive) khi deserialize
- Dùng cho: password, token, cache, calculated fields, non-serializable objects
3. Custom Serialization (Nâng cao)
private void writeObject(ObjectOutputStream out) throws IOException {
out.defaultWriteObject();
// Custom write logic
out.writeObject(encryptedPassword);
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
// Custom read logic
encryptedPassword = (String) in.readObject();
password = decrypt(encryptedPassword);
}
4. Serializable với Collection
// List/Set/Map cũng implement Serializable nếu element cũng Serializable
List<SerializableObject> userList = new ArrayList<>();
userList.add(new SerializableObject("A", 1, "p1"));
userList.add(new SerializableObject("B", 2, "p2"));
intent.putExtra("user_list", (Serializable) userList); // Cast cần thiết
// Nhận
List<SerializableObject> received = (List<SerializableObject>) intent.getSerializableExtra("user_list");
Hạn chế của Serializable
- Chậm: Dùng reflection, tạo nhiều object tạm
- Kích thước lớn: Byte stream verbose
- Không an toàn: Có thể bị tấn công qua deserialize (malicious data)
- Không phù hợp: High-frequency IPC, large data, performance-critical
Khi nào dùng Serializable?
- Dữ liệu nhỏ, đơn giản
- Truyền qua Intent/Bundle không quá thường xuyên
- Lưu trữ file local (SharedPreferences không hỗ trợ object trực tiếp)
- Tương thích Java thuần túy (non-Android)
- Prototype, MVP, development nhanh
Khuyến nghị: Dùng Parcelable cho Android
Xem bài "Làm thế nào để custom object có thể Parcelable" để biết cách triển khai hiệu năng cao hơn.