Trình tạo lượt triển khai Parcelable

Trình bổ trợ kotlin-parcelize cung cấp một trình tạo lượt triển khai Parcelable.

Để hỗ trợ Parcelable, hãy thêm trình bổ trợ Gradle vào tệp build.gradle của ứng dụng:

Groovy

plugins {
    id 'kotlin-parcelize'
}

Kotlin

plugins {
    id("kotlin-parcelize")
}

Khi bạn chú thích một lớp (class) bằng @Parcelize, phương thức triển khai Parcelable sẽ tự động được tạo, như trong ví dụ sau:

import kotlinx.parcelize.Parcelize

@Parcelize
class User(val firstName: String, val lastName: String, val age: Int): Parcelable

@Parcelize đòi hỏi khai báo tất cả thuộc tính tuần tự trong hàm khởi tạo chính. Trình bổ trợ này cảnh báo về từng thuộc tính có một trường sao lưu được khai báo trong nội dung lớp. Ngoài ra, bạn không thể áp dụng @Parcelize nếu một số tham số của hàm khởi tạo chính không phải là thuộc tính.

Nếu lớp của bạn yêu cầu logic tuần tự hoá nâng cao hơn, hãy ghi lớp này vào trong lớp đồng hành (companion class):

@Parcelize
data class User(val firstName: String, val lastName: String, val age: Int) : Parcelable {
    private companion object : Parceler<User> {
        override fun User.write(parcel: Parcel, flags: Int) {
            // Custom write implementation
        }

        override fun create(parcel: Parcel): User {
            // Custom read implementation
        }
    }
}

Các kiểu được hỗ trợ

@Parcelize hỗ trợ nhiều kiểu:

  • Kiểu nguyên bản (và các phiên bản đóng hộp)
  • Đối tượng và enum
  • String, CharSequence
  • Duration
  • Exception
  • Size, SizeF, Bundle, IBinder, IInterface, FileDescriptor
  • SparseArray, SparseIntArray, SparseLongArray, SparseBooleanArray
  • Tất cả cách triển khai Serializable (bao gồm cả Date) và Parcelable
  • Bộ sưu tập toàn bộ kiểu được hỗ trợ: List (được ánh xạ tới ArrayList), Set (được ánh xạ tới LinkedHashSet), Map (được ánh xạ tới LinkedHashMap)
    • Ngoài ra, có một số cách triển khai cụ thể: ArrayList, LinkedList, SortedSet, NavigableSet, HashSet, LinkedHashSet, TreeSet, SortedMap, NavigableMap, HashMap, LinkedHashMap, TreeMap, ConcurrentHashMap
  • Mảng (array) thuộc mọi kiểu được hỗ trợ
  • Phiên bản có tính chất rỗng của mọi kiểu được hỗ trợ

Parceler tuỳ chỉnh

Nếu kiểu của bạn không được hỗ trợ trực tiếp, bạn có thể viết một đối tượng ánh xạ Parceler cho kiểu đó.

class ExternalClass(val value: Int)

object ExternalClassParceler : Parceler<ExternalClass> {
    override fun create(parcel: Parcel) = ExternalClass(parcel.readInt())

    override fun ExternalClass.write(parcel: Parcel, flags: Int) {
        parcel.writeInt(value)
    }
}

Bạn có thể áp dụng các trình đóng gói (parceler) bên ngoài bằng chú thích @TypeParceler hoặc @WriteWith:

// Class-local parceler
@Parcelize
@TypeParceler<ExternalClass, ExternalClassParceler>()
class MyClass(val external: ExternalClass) : Parcelable

// Property-local parceler
@Parcelize
class MyClass(@TypeParceler<ExternalClass, ExternalClassParceler>() val external: ExternalClass) : Parcelable

// Type-local parceler
@Parcelize
class MyClass(val external: @WriteWith<ExternalClassParceler>() ExternalClass) : Parcelable

Bỏ qua các thuộc tính khỏi quá trình chuyển đổi tuần tự

Nếu bạn muốn bỏ qua việc phân loại một số thuộc tính, hãy sử dụng thuộc tính Chú giải @IgnoredOnParcel. Bạn cũng có thể dùng công cụ này trên các tài sản trong phần nội dung của lớp để tắt tiếng các cảnh báo về việc thuộc tính không được chuyển đổi tuần tự. Thuộc tính hàm khởi tạo được chú thích bằng @IgnoredOnParcel phải có giá trị mặc định giá trị.

@Parcelize
class MyClass(
    val include: String,
    // Don't serialize this property
    @IgnoredOnParcel val ignore: String = "default"
): Parcelable {
    // Silence a warning
    @IgnoredOnParcel
    val computed: String = include + ignore
}

Sử dụng android.os.Parcel.writeValue để chuyển đổi tuần tự một thuộc tính

Bạn có thể chú thích một loại bằng @RawValue để sử dụng Phân vùng Parcel.writeValue cho tài sản đó.

@Parcelize
class MyClass(val external: @RawValue ExternalClass): Parcelable

Thao tác này có thể không thực hiện được trong thời gian chạy nếu giá trị của thuộc tính không được Android hỗ trợ vốn có.

Bạn cũng có thể phải sử dụng chú thích này khi không có chú thích nào khác để tuần tự hoá thuộc tính.

Đóng gói bằng các lớp kín và giao diện kín

Việc phân vùng yêu cầu phải phân vùng một lớp sao cho không phải là lớp trừu tượng. Giới hạn này không được lưu giữ đối với các lớp kín. Khi chú thích @Parcelize được sử dụng trên một lớp kín, bạn không cần lặp lại chú thích này cho các lớp phái sinh.

@Parcelize
sealed class SealedClass: Parcelable {
    class A(val a: String): SealedClass()
    class B(val b: Int): SealedClass()
}

@Parcelize
class MyClass(val a: SealedClass.A, val b: SealedClass.B, val c: SealedClass): Parcelable

Phản hồi

Nếu gặp vấn đề với trình bổ trợ kotlin-parcelize cho Gradle, bạn có thể báo cáo lỗi.