Il plug-in kotlin-parcelize fornisce un generatore di implementazione Parcelable.
Per includere il supporto di Parcelable, aggiungi il plug-in Gradle al file build.gradle della tua app:
Alla moda
plugins { id 'kotlin-parcelize' }
Kotlin
plugins { id("kotlin-parcelize") }
Quando annoti una classe con @Parcelize, viene generata automaticamente un'implementazione di Parcelable, come mostrato nell'esempio seguente:
// import kotlinx.parcelize.Parcelize @Parcelize class User(val firstName: String, val lastName: String, val age: Int) : Parcelable
@Parcelize richiede che tutte le proprietà serializzate vengano dichiarate nel costruttore principale. Il plug-in genera un avviso per ogni proprietà
con un campo di supporto dichiarato nel corpo della classe. Inoltre, non puoi
applicare @Parcelize se alcuni parametri del costruttore primario non sono
proprietà.
Se la tua classe richiede una logica di serializzazione più avanzata, scrivila all'interno di una classe complementare:
@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 } } }
Tipi supportati
@Parcelize supporta un'ampia gamma di tipi:
- Tipi primitivi (e relative versioni boxed)
- Oggetti ed enumerazioni
String,CharSequenceDurationExceptionSize,SizeF,Bundle,IBinder,IInterface,FileDescriptorSparseArray,SparseIntArray,SparseLongArray,SparseBooleanArray- Tutte le implementazioni di
Serializable(inclusoDate) eParcelable - Raccolte di tutti i tipi supportati:
List(mappato aArrayList),Set(mappato aLinkedHashSet),Map(mappato aLinkedHashMap)- Inoltre, sono disponibili diverse implementazioni concrete:
ArrayList,LinkedList,SortedSet,NavigableSet,HashSet,LinkedHashSet,TreeSet,SortedMap,NavigableMap,HashMap,LinkedHashMap,TreeMap,ConcurrentHashMap
- Inoltre, sono disponibili diverse implementazioni concrete:
- Array di tutti i tipi supportati
- Versioni Nullable di tutti i tipi supportati
Parceler personalizzati
Se il tuo tipo non è supportato direttamente, puoi scrivere un oggetto di mappatura 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) } }
Puoi applicare i parceler esterni utilizzando le annotazioni @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
Creare dati da Parcel
Nel codice Java, puoi accedere direttamente al campo CREATOR.
class UserCreator {
static User fromParcel(Parcel parcel) {
return User.CREATOR.createFromParcel(parcel);
}
}
In Kotlin, non puoi utilizzare direttamente il campo CREATOR. Utilizza invece
kotlinx.parcelize.parcelableCreator.
// import kotlinx.parcelize.parcelableCreator fun userFromParcel(parcel: Parcel): User { return parcelableCreator<User>().createFromParcel(parcel) }
Skip properties from serialization (Escludi proprietà dalla serializzazione)
Se vuoi escludere alcune proprietà dalla suddivisione in pacchetti, utilizza l'annotazione
@IgnoredOnParcel. Può essere utilizzato anche nelle proprietà all'interno del corpo di una classe per disattivare gli avvisi relativi alla proprietà non serializzata.
Le proprietà del costruttore annotate con @IgnoredOnParcel devono avere un valore predefinito.
@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 }
Utilizza android.os.Parcel.writeValue per serializzare una proprietà
Puoi annotare un tipo con @RawValue per fare in modo che Parcelize utilizzi
Parcel.writeValue per quella proprietà.
@Parcelize class MyClass(val external: @RawValue ExternalClass) : Parcelable
L'operazione potrebbe non riuscire in fase di runtime se il valore della proprietà non è supportato in modo nativo da Android.
Parcelize potrebbe anche richiedere l'utilizzo di questa annotazione quando non esiste un altro modo per serializzare la proprietà.
Parcelizzazione con classi sigillate e interfacce sigillate
Parcelize richiede che una classe da serializzare non sia astratta. Questa limitazione non
vale per le classi sigillate. Quando l'annotazione @Parcelize viene utilizzata in una
classe sealed, non è necessario ripeterla per le classi derivate.
@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
Configurare Parcelize per Kotlin Multiplatform
Prima di Kotlin 2.0, potevi utilizzare Parcelize creando alias delle annotazioni Parcelize
con expect e actual:
// Common code
package example
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.BINARY)
expect annotation class MyParcelize()
expect interface MyParcelable
@Target(AnnotationTarget.PROPERTY)
@Retention(AnnotationRetention.SOURCE)
expect annotation class MyIgnoredOnParcel()
@MyParcelize
class MyClass(
val x: String,
@MyIgnoredOnParcel val y: String = ""
): MyParcelable
// Platform code
package example
actual typealias MyParcelize = kotlinx.parcelize.Parcelize
actual typealias MyParcelable = android.os.Parcelable
actual typealias MyIgnoredOnParcel = kotlinx.parcelize.IgnoredOnParcel
In Kotlin 2.0 e versioni successive, l'aliasing delle annotazioni che attivano i plug-in non è supportato. Per aggirare questo problema, fornisci una nuova annotazione Parcelize come parametro additionalAnnotation al plug-in.
// Gradle build configuration
kotlin {
androidTarget {
compilerOptions {
// ...
freeCompilerArgs.addAll("-P", "plugin:org.jetbrains.kotlin.parcelize:additionalAnnotation=example.MyParcelize")
}
}
}
// Common code // package example @Target(AnnotationTarget.CLASS) @Retention(AnnotationRetention.BINARY) // No `expect` keyword here annotation class MyParcelize() expect interface MyParcelable @Target(AnnotationTarget.PROPERTY) @Retention(AnnotationRetention.SOURCE) expect annotation class MyIgnoredOnParcel() @MyParcelize class MyClass( val x: String, @MyIgnoredOnParcel val y: String = "" ) : MyParcelable
// Platform code // package example // No typealias for MyParcelize here actual typealias MyParcelable = android.os.Parcelable actual typealias MyIgnoredOnParcel = kotlinx.parcelize.IgnoredOnParcel
Poiché l'interfaccia Parcel è disponibile solo su Android, Parcelize non genererà codice su altre piattaforme, quindi qualsiasi implementazione di actual può essere vuota. Inoltre, non è possibile utilizzare annotazioni che
richiedono il riferimento alla classe Parcel, ad esempio
@WriteWith, nel codice comune.
Funzionalità sperimentali
Serializzatore della classe di dati
Disponibile a partire da Kotlin 2.1.0.
L'annotazione DataClass consente di serializzare le classi di dati come se fossero
annotate con Parcelize. Questa annotazione richiede
l'attivazione di kotlinx.parcelize.Experimental.
// @file:OptIn(kotlinx.parcelize.Experimental::class) data class C(val a: Int, val b: String) @Parcelize class P(val c: @DataClass C) : Parcelable
Il costruttore principale e tutte le relative proprietà devono essere accessibili dalla classe Parcelable. Inoltre, tutte le proprietà del costruttore principale della
classe di dati devono essere supportate da Parcelize.
Se selezionati, i Custom Parcelers devono essere specificati nella classe
Parcelable, non nella classe di dati.
Se la classe di dati implementa Serializable contemporaneamente, l'annotazione @DataClass
ha la priorità:
android.os.Parcel.writeSerializable
non verrà utilizzata.
Un caso d'uso pratico è la serializzazione di kotlin.Pair.
Un altro esempio utile è la semplificazione del
codice multipiattaforma: il codice comune potrebbe dichiarare il data layer come classi di dati, che il codice Android
potrebbe poi aumentare con la logica di serializzazione, eliminando la necessità di
annotazioni e alias di tipo specifici per Android nel codice comune.
// Common code: data class MyData(val x: String, val y: MoreData) data class MoreData(val a: String, val b: Int) // Platform code: @OptIn(kotlinx.parcelize.Experimental::class) @Parcelize class DataWrapper(val wrapped: @DataClass MyData) : Parcelable
Parametri non val o var nel costruttore principale
Disponibile a partire da Kotlin 2.1.0.
Per attivare questa funzionalità, aggiungi experimentalCodeGeneration=true agli argomenti del plug-in parcelize.
kotlin {
compilerOptions {
// ...
freeCompilerArgs.addAll("-P", "plugin:org.jetbrains.kotlin.parcelize:experimentalCodeGeneration=true")
}
}
Questa funzionalità elimina la limitazione secondo cui gli argomenti del costruttore primario devono essere
val o var. In questo modo si risolve un problema dell'utilizzo di parcelize con l'ereditarietà, che in precedenza richiedeva l'utilizzo delle proprietà open.
// base parcelize @Parcelize open class Base(open val s: String) : Parcelable @Parcelize class Derived( val x: Int, // all arguments have to be `val` or `var` so we need to override // to not introduce new property name override val s: String ) : Base(s)
// experimental code generation enabled
@Parcelize
open class Base(val s: String): Parcelable
@Parcelize
class Derived(val x: Int, s: String): Base(s)
Questi parametri possono essere utilizzati solo negli argomenti del costruttore della classe base. Non è consentito farvi riferimento nel corpo della classe.
@Parcelize
class Derived(s: String): Base(s) { // allowed
@IgnoredOnParcel
val x: String = s // ERROR: not allowed.
init {
println(s) // ERROR: not allowed
}
}
Feedback
Se riscontri problemi con il kotlin-parcelizeplugin Gradle, puoi
segnalare un bug.