Das kotlin-parcelize-Plug-in bietet einen Generator für die Implementierung von Parcelable.
Wenn Sie Unterstützung für Parcelable hinzufügen möchten, fügen Sie das Gradle-Plug-in der Datei build.gradle Ihrer App hinzu:
Groovy
plugins { id 'kotlin-parcelize' }
Kotlin
plugins { id("kotlin-parcelize") }
Wenn Sie eine Klasse mit @Parcelize annotieren, wird automatisch eine Parcelable-Implementierung generiert, wie im folgenden Beispiel gezeigt:
// import kotlinx.parcelize.Parcelize @Parcelize class User(val firstName: String, val lastName: String, val age: Int) : Parcelable
Für @Parcelize müssen alle serialisierten Properties im primären Konstruktor deklariert werden. Das Plug-in gibt für jede Property mit einem im Klassenrumpf deklarierten Backing Field eine Warnung aus. Außerdem können Sie @Parcelize nicht anwenden, wenn einige der primären Konstruktorparameter keine Attribute sind.
Wenn für Ihre Klasse eine komplexere Serialisierungslogik erforderlich ist, schreiben Sie sie in eine Companion-Klasse:
@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 } } }
Unterstützte Typen
@Parcelize unterstützt eine Vielzahl von Typen:
- Einfache Typen (und ihre boxed-Versionen)
- Objekte und Enums
String,CharSequenceDurationExceptionSize,SizeF,Bundle,IBinder,IInterface,FileDescriptorSparseArray,SparseIntArray,SparseLongArray,SparseBooleanArray- Alle
Serializable-Implementierungen (einschließlichDate) undParcelable-Implementierungen - Sammlungen aller unterstützten Typen:
List(zugeordnet zuArrayList),Set(zugeordnet zuLinkedHashSet),Map(zugeordnet zuLinkedHashMap)- Außerdem gibt es eine Reihe konkreter Implementierungen:
ArrayList,LinkedList,SortedSet,NavigableSet,HashSet,LinkedHashSet,TreeSet,SortedMap,NavigableMap,HashMap,LinkedHashMap,TreeMap,ConcurrentHashMap
- Außerdem gibt es eine Reihe konkreter Implementierungen:
- Arrays aller unterstützten Typen
- Nullable-Versionen aller unterstützten Typen
Benutzerdefiniert Parceler
Wenn Ihr Typ nicht direkt unterstützt wird, können Sie ein Parceler-Zuordnungsobjekt dafür schreiben.
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) } }
Sie können externe Parceler mit den Annotationen @TypeParceler oder @WriteWith anwenden:
// 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
Daten aus Parcel erstellen
Im Java-Code können Sie direkt auf das Feld CREATOR zugreifen.
class UserCreator {
static User fromParcel(Parcel parcel) {
return User.CREATOR.createFromParcel(parcel);
}
}
In Kotlin können Sie das Feld CREATOR nicht direkt verwenden. Verwenden Sie stattdessen kotlinx.parcelize.parcelableCreator.
// import kotlinx.parcelize.parcelableCreator fun userFromParcel(parcel: Parcel): User { return parcelableCreator<User>().createFromParcel(parcel) }
Properties von der Serialisierung ausschließen
Wenn Sie verhindern möchten, dass eine Property serialisiert wird, verwenden Sie die Annotation @IgnoredOnParcel. Es kann auch für Attribute im Hauptteil einer Klasse verwendet werden, um Warnungen zu unterdrücken, dass das Attribut nicht serialisiert wird.
Für Konstruktorattribute, die mit @IgnoredOnParcel annotiert sind, muss ein Standardwert angegeben werden.
@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 }
android.os.Parcel.writeValue zum Serialisieren eines Attributs verwenden
Sie können einen Typ mit @RawValue annotieren, damit Parcelize Parcel.writeValue für diese Eigenschaft verwendet.
@Parcelize class MyClass(val external: @RawValue ExternalClass) : Parcelable
Dies kann zur Laufzeit fehlschlagen, wenn der Wert der Property nicht von Android unterstützt wird.
Möglicherweise müssen Sie diese Annotation auch verwenden, wenn es keine andere Möglichkeit gibt, das Attribut zu serialisieren.
Parcelize mit versiegelten Klassen und versiegelten Schnittstellen
Für die Parcelize-Annotation muss die zu serialisierende Klasse nicht abstrakt sein. Diese Einschränkung gilt nicht für versiegelte Klassen. Wenn die Annotation @Parcelize für eine versiegelte Klasse verwendet wird, muss sie für die abgeleiteten Klassen nicht wiederholt werden.
@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
Parcelize für Kotlin Multiplatform einrichten
Vor Kotlin 2.0 konnten Sie Parcelize verwenden, indem Sie Parcelize-Annotationen mit expect und actual aliasieren:
// 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 und höher werden Alias-Annotationen, die Plug-ins auslösen, nicht unterstützt. Um dies zu umgehen, geben Sie stattdessen eine neue Parcelize-Annotation als additionalAnnotation-Parameter für das Plug-in an.
// 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
Da die Parcel-Schnittstelle nur auf Android verfügbar ist, generiert Parcelize auf anderen Plattformen keinen Code. Alle actual-Implementierungen können dort also leer sein. Außerdem ist es nicht möglich, eine Annotation zu verwenden, für die auf die Klasse Parcel verwiesen werden muss, z. B. @WriteWith, in gemeinsamem Code.
Experimentelle Funktionen
Bei Problemen können Sie uns gerne Feedback geben.Serialisierung von Datenklassen
Verfügbar seit Kotlin 2.1.0.
Mit der Annotation DataClass können Datenklassen so serialisiert werden, als wären sie selbst mit Parcelize annotiert. Für diese Anmerkung ist die Einwilligung von kotlinx.parcelize.Experimental erforderlich.
// @file:OptIn(kotlinx.parcelize.Experimental::class) data class C(val a: Int, val b: String) @Parcelize class P(val c: @DataClass C) : Parcelable
Der primäre Konstruktor und alle seine Eigenschaften müssen über die Klasse Parcelable zugänglich sein. Außerdem müssen alle primären Konstruktoreigenschaften der Datenklasse von Parcelize unterstützt werden.
Benutzerdefinierte Parceler müssen, falls ausgewählt, in der Parcelable-Klasse und nicht in der Datenklasse angegeben werden.
Wenn die Datenklasse gleichzeitig Serializable implementiert, hat die Annotation @DataClass Priorität: android.os.Parcel.writeSerializable wird nicht verwendet.
Ein praktischer Anwendungsfall dafür ist die Serialisierung von kotlin.Pair.
Ein weiteres nützliches Beispiel ist die Vereinfachung von Multiplattform-Code: Im gemeinsamen Code könnte die Datenschicht als Datenklassen deklariert werden, die dann im Android-Code mit Serialisierungslogik erweitert werden. So sind keine Android-spezifischen Annotationen und Typ-Aliase im gemeinsamen Code mehr erforderlich.
// 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
Nicht-val- oder -var-Parameter im primären Konstruktor
Verfügbar seit Kotlin 2.1.0.
Um diese Funktion zu aktivieren, fügen Sie experimentalCodeGeneration=true den Argumenten des Parcelize-Plug-ins hinzu.
kotlin {
compilerOptions {
// ...
freeCompilerArgs.addAll("-P", "plugin:org.jetbrains.kotlin.parcelize:experimentalCodeGeneration=true")
}
}
Diese Funktion hebt die Einschränkung auf, dass Primärkonstruktorargumente val oder var sein müssen. Dadurch wird ein Problem bei der Verwendung von „parcelize“ mit Vererbung behoben, für das zuvor open-Properties erforderlich waren.
// 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)
Solche Parameter dürfen nur in Argumenten für den Konstruktor der Basisklasse verwendet werden. Es ist nicht zulässig, im Hauptteil der Klasse darauf zu verweisen.
@Parcelize
class Derived(s: String): Base(s) { // allowed
@IgnoredOnParcel
val x: String = s // ERROR: not allowed.
init {
println(s) // ERROR: not allowed
}
}
Feedback
Wenn Sie Probleme mit dem kotlin-parcelize-Gradle-Plug-in haben, können Sie einen Fehler melden.