Generador de implementaciones Parcelable

El complemento kotlin-parcelize proporciona un generador de implementaciones Parcelable.

Para incluir compatibilidad con Parcelable, agrega el complemento de Gradle al archivo build.gradle de tu app:

Groovy

plugins {
    id 'kotlin-parcelize'
}

Kotlin

plugins {
    id("kotlin-parcelize")
}

Cuando anotas una clase con @Parcelize, se genera automáticamente una implementación Parcelable, como se muestra en el siguiente ejemplo:

import kotlinx.parcelize.Parcelize

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

@Parcelize requiere que todas las propiedades serializadas se declaren en el constructor principal. El complemento emite una advertencia en cada propiedad con un campo de respaldo declarado en el cuerpo de la clase. Además, no puedes aplicar @Parcelize si algunos de los parámetros del constructor principal no son propiedades.

Si tu clase requiere una lógica de serialización más avanzada, escríbela dentro de una clase complementaria:

@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
        }
    }
}

Tipos admitidos

@Parcelize admite una amplia variedad de tipos:

  • Tipos primitivos (y sus versiones encuadrados)
  • Objetos y enumeraciones
  • String, CharSequence
  • Duration
  • Exception
  • Size, SizeF, Bundle, IBinder, IInterface, FileDescriptor
  • SparseArray, SparseIntArray, SparseLongArray, SparseBooleanArray
  • Todas las implementaciones de Serializable (incluidas Date) y Parcelable
  • Colecciones de todos los tipos compatibles: List (mapeado a ArrayList), Set (mapeado a LinkedHashSet), Map (mapeado a LinkedHashMap)
    • También hay una cantidad de implementaciones concretas: ArrayList, LinkedList, SortedSet, NavigableSet, HashSet, LinkedHashSet, TreeSet y SortedMap, NavigableMap, HashMap, LinkedHashMap, TreeMap, ConcurrentHashMap
  • Arreglos de todos los tipos compatibles
  • Versiones anulables de todos los tipos compatibles

Parceler personalizados

Si tu tipo no se admite directamente, puedes escribir un objeto de mapeo Parceler.

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)
    }
}

Puedes aplicar paquetes externos mediante las anotaciones @TypeParceler o @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

Omitir propiedades de la serialización

Si quieres omitir que se parcele una propiedad, usa la anotación @IgnoredOnParcel. También se puede usar en propiedades dentro de el cuerpo de la clase para silenciar las advertencias que indican que la propiedad no se serializa. Las propiedades del constructor con anotaciones @IgnoredOnParcel deben tener un valor predeterminado valor.

@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
}

Usa android.os.Parcel.writeValue para serializar una propiedad

Puedes anotar un tipo con @RawValue para que se use Parcelize. Parcel.writeValue para esa propiedad.

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

Esto puede fallar en el tiempo de ejecución si el valor de la propiedad no es compatibles con Android de forma nativa.

Parcelize también puede requerir que uses esta anotación cuando no haya otra de serialización de la propiedad.

Parcela con interfaces y clases selladas

Parcelize requiere una clase para parcelize para que no sea abstracta. Esta limitación no para las clases selladas. Cuando se usa la anotación @Parcelize en un sellada, no es necesario que se repita para las clases derivadas.

@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

Comentarios

Si tienes algún problema con el complemento kotlin-parcelize de Gradle, informa un error.