Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Android

Làm thế nào để custom object có thể Serializable trên Android

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 → InvalidClassException khi 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.