Das kotlin-parcelize
-Plug-in bietet einen Parcelable
-Implementierungsgenerator.
Wenn Sie Parcelable
unterstützen möchten, fügen Sie der Datei build.gradle
Ihrer App das Gradle-Plug-in 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 Klassenkörper deklarierten Back-End-Feld eine Warnung aus. Außerdem können Sie @Parcelize
nicht anwenden, wenn einige der primären Konstruktorparameter keine Eigenschaften sind.
Wenn Ihre Klasse eine erweiterte Serialisierungslogik benötigt, 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
,CharSequence
Duration
Exception
Size
,SizeF
,Bundle
,IBinder
,IInterface
,FileDescriptor
SparseArray
,SparseIntArray
,SparseLongArray
,SparseBooleanArray
- Alle
Serializable
- (einschließlichDate
-) undParcelable
-Implementierungen - Sammlungen aller unterstützten Typen:
List
(aufArrayList
zugeordnet),Set
(aufLinkedHashSet
zugeordnet),Map
(aufLinkedHashMap
zugeordnet)- Einige konkrete Implementierungen:
ArrayList
,LinkedList
,SortedSet
,NavigableSet
,HashSet
,LinkedHashSet
,TreeSet
,SortedMap
,NavigableMap
,HashMap
,LinkedHashMap
,TreeMap
undConcurrentHashMap
- Einige konkrete Implementierungen:
- Arrays aller unterstützten Typen
- Nullable Versionen aller unterstützten Typen
Benutzerdefinierte Parceler
s
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 Pakete 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 Grundstück 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)
}
Eigenschaften bei der Serialisierung überspringen
Wenn Sie ein Attribut überspringen möchten, verwenden Sie die Annotation @IgnoredOnParcel
. Sie kann auch für Properties im Body einer Klasse verwendet werden, um Warnungen zu unterdrücken, dass die Property nicht serialisiert wird.
Mit @IgnoredOnParcel
annotierte Konstruktoreigenschaften müssen einen Standardwert haben.
@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 einer Property verwenden
Sie können einen Typ mit @RawValue
annotieren, damit Parcelize Parcel.writeValue
für dieses Attribut verwendet.
@Parcelize
class MyClass(val external: @RawValue ExternalClass): Parcelable
Dies kann zur Laufzeit fehlschlagen, wenn der Wert der Property nicht nativ von Android unterstützt wird.
Möglicherweise müssen Sie diese Anmerkung auch verwenden, wenn es keine andere Möglichkeit gibt, die Property zu serialisieren.
Mit versiegelten Klassen und versiegelten Schnittstellen paketieren
Für die Funktion „Parcelize“ darf die zu parzellierende Klasse nicht abstrakt sein. Diese Einschränkung gilt nicht für versiegelte Klassen. Wenn die @Parcelize
-Anmerkung für eine versiegelte Klasse verwendet wird, muss sie nicht für die abgeleiteten Klassen 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 Aliasse für Parcelize-Anmerkungen mit expect
und actual
erstellt haben:
// 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-Anmerkungen, die Plugins auslösen, nicht unterstützt. Um dies zu umgehen, gib stattdessen eine neue Parcelize
-Anmerkung 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-Geräten verfügbar ist, generiert Parcelize auf anderen Plattformen keinen Code. Daher können dort vorhandene actual
-Implementierungen leer sein. Außerdem können keine Anmerkungen verwendet werden, die im gemeinsamen Code auf die Parcel
-Klasse verweisen müssen, z. B. @WriteWith
.
Experimentelle Funktionen
Datenklassen-Serializer
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 Aktivierung 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 Properties müssen von der Klasse Parcelable
aus zugänglich sein. Außerdem müssen alle primären Konstruktoreigenschaften der Datenklasse von Parcelize
unterstützt werden.
Benutzerdefinierte Parcelers sollten, falls ausgewählt, in der Klasse Parcelable
und nicht in der Datenklasse angegeben werden.
Wenn die Datenklasse gleichzeitig Serializable
implementiert, hat die @DataClass
-Anmerkung Vorrang: 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 plattformübergreifendem Code: Üblicher Code könnte die Datenschicht als Datenklassen deklarieren, die der Android-Code dann mit Serialisierungslogik erweitern könnte. Dadurch sind Android-spezifische Anmerkungen und Typaliasse im gemeinsamen Code nicht 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.
Wenn Sie diese Funktion aktivieren möchten, fügen Sie den Plugin-Argumenten für „parcelize“ experimentalCodeGeneration=true
hinzu.
kotlin {
compilerOptions {
// ...
freeCompilerArgs.addAll("-P", "plugin:org.jetbrains.kotlin.parcelize:experimentalCodeGeneration=true")
}
}
Mit dieser Funktion wird die Beschränkung für primäre Konstruktorargumente aufgehoben, die val
oder var
sein müssen. Damit wird ein Problem bei der Verwendung von „parcelize“ mit Vererbung gelöst, für das bisher 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. Verweise darauf im Body der Klasse sind nicht zulässig.
@Parcelize
class Derived(s: String): Base(s) { // allowed
@IgnoredOnParcel
val x: String = s // ERROR: not allowed.
init {
println(s) // ERROR: not allowed
}
}
Feedback
Wenn Probleme mit dem kotlin-parcelize
Gradle-Plug-in auftreten, können Sie einen Fehler melden.