Il plug-in kotlin-parcelize
fornisce un generatore di implementazione Parcelable
.
Per includere il supporto di Parcelable
, aggiungi il plug-in Gradle al file Parcelable
dell'app:build.gradle
Groovy
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 siano dichiarate nel costruttore principale. Il plug-in invia un avviso per ogni proprietà
con un campo di supporto dichiarato nel corpo della classe. Inoltre, non puoi
applicare @Parcelize
se alcuni dei parametri del costruttore principale non sono
proprietà.
Se la classe richiede una logica di serializzazione più avanzata, scrivila in 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 le relative versioni con casella)
- Oggetti ed enum
String
,CharSequence
Duration
Exception
Size
,SizeF
,Bundle
,IBinder
,IInterface
eFileDescriptor
SparseArray
,SparseIntArray
,SparseLongArray
,SparseBooleanArray
- Tutte le implementazioni di
Serializable
(inclusoDate
) eParcelable
- Collezioni di tutti i tipi supportati:
List
(mappata aArrayList
),Set
(mappata aLinkedHashSet
),Map
(mappata aLinkedHashMap
)- Inoltre, una serie di implementazioni concrete:
ArrayList
,LinkedList
,SortedSet
,NavigableSet
,HashSet
,LinkedHashSet
,TreeSet
,SortedMap
,NavigableMap
,HashMap
,LinkedHashMap
,TreeMap
,ConcurrentHashMap
- Inoltre, una serie di implementazioni concrete:
- Array di tutti i tipi supportati
- Versioni con valori null di tutti i tipi supportati
Parceler
personalizzati
Se il tipo non è supportato direttamente, puoi scrivere un Parceler
oggetto di mappatura per questo.
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 parcellatori 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)
}
Saltare le proprietà dalla serializzazione
Se vuoi saltare il parcellamento di alcune proprietà, utilizza l'annotazione @IgnoredOnParcel
. Può essere utilizzato anche per le proprietà all'interno del corpo di una classe per disattivare gli avvisi relativi alla mancata serializzazione della proprietà.
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
}
Utilizzare android.os.Parcel.writeValue per la serializzazione di 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.
La pacchettizzazione potrebbe anche richiedere di utilizzare questa annotazione quando non esiste un altro modo per serializzare la proprietà.
Suddividi in pacchetti con classi e interfacce sigillate
Per la pacchettizzazione, la partizione deve essere una classe non astratta. Questa limitazione non vale per le classi sigillate. Quando l'annotazione @Parcelize
viene utilizzata in una classe sigillata, non deve essere ripetuta 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
Configura la Parcelize per la multipiattaforma Kotlin
Prima di Kotlin 2.0, potevi utilizzare Parcelize creando un alias per le 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, le annotazioni di alias che attivano i plug-in non sono supportate. Per aggirare il problema, fornisci al plug-in una nuova annotazione Parcelize
come parametro additionalAnnotation
.
// 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, l'applicazione Parcelize non
genera codice su altre piattaforme, pertanto eventuali implementazioni actual
possono essere vuote. Inoltre, non è possibile utilizzare nessuna annotazione che
richiede fare riferimento alla classe Parcel
, ad esempio
@WriteWith
, nel codice comune.
Funzionalità sperimentali
Serializzatore della classe di dati
Disponibile 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 sue proprietà devono essere accessibili dalla classe
Parcelable
. Inoltre, tutte le proprietà del costruttore principale della classe di dati devono essere supportate da Parcelize
.
I partizionatori personalizzati, se scelti, devono essere specificati nel
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 livello dati come classi di dati, che il codice Android potrebbe poi integrare 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 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 sugli argomenti principali del costruttore che devono essere
val
o var
. In questo modo viene risolto uno dei problemi dell'utilizzo di parcelize con l'eredità,
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 constructor della classe di base. Non è consentito fare riferimento a questi contenuti nel corpo del corso.
@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 plug-in Gradle kotlin-parcelize
, puoi segnalare un bug.