kotlin-parcelizeWtyczka udostępnia generator implementacji Parcelable.
Aby uwzględnić obsługę Parcelable, dodaj wtyczkę Gradle do pliku build.gradle aplikacji:
Dynamiczny
plugins { id 'kotlin-parcelize' }
Kotlin
plugins { id("kotlin-parcelize") }
Gdy dodasz do klasy adnotację @Parcelize, automatycznie zostanie wygenerowana implementacja Parcelable, jak pokazano w tym przykładzie:
// import kotlinx.parcelize.Parcelize @Parcelize class User(val firstName: String, val lastName: String, val age: Int) : Parcelable
@Parcelize wymaga, aby wszystkie serializowane właściwości były zadeklarowane w konstruktorze głównym. Wtyczka wyświetla ostrzeżenie dotyczące każdej właściwości, która ma pole zapasowe zadeklarowane w treści klasy. Nie możesz też zastosować @Parcelize, jeśli niektóre parametry konstruktora głównego nie są właściwościami.
Jeśli Twoja klasa wymaga bardziej zaawansowanej logiki serializacji, napisz ją w klasie towarzyszącej:
@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 } } }
Obsługiwane typy
@Parcelize obsługuje szeroką gamę typów:
- Typy proste (i ich wersje opakowane)
- Obiekty i wyliczenia
String,CharSequenceDurationExceptionSize,SizeF,Bundle,IBinder,IInterface,FileDescriptorSparseArray,SparseIntArray,SparseLongArray,SparseBooleanArray- Wszystkie implementacje
Serializable(w tymDate) iParcelable - Kolekcje wszystkich obsługiwanych typów:
List(mapowane naArrayList),Set(mapowane naLinkedHashSet),Map(mapowane naLinkedHashMap)- Istnieje też wiele konkretnych implementacji:
ArrayList,LinkedList,SortedSet,NavigableSet,HashSet,LinkedHashSet,TreeSet,SortedMap,NavigableMap,HashMap,LinkedHashMap,TreeMap,ConcurrentHashMap
- Istnieje też wiele konkretnych implementacji:
- Tablice wszystkich obsługiwanych typów
- Wersje dopuszczające wartość null wszystkich obsługiwanych typów
Niestandardowe Parceler
Jeśli Twój typ nie jest obsługiwany bezpośrednio, możesz utworzyć dla niego Parcelerobiekt mapowania.
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) } }
Możesz zastosować zewnętrzne narzędzia do analizy składni za pomocą adnotacji @TypeParceler lub @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
Tworzenie danych z Parcel
W kodzie Java możesz uzyskać dostęp do pola CREATOR bezpośrednio.
class UserCreator {
static User fromParcel(Parcel parcel) {
return User.CREATOR.createFromParcel(parcel);
}
}
W języku Kotlin nie możesz używać pola CREATOR bezpośrednio. Zamiast tego użyj zasady kotlinx.parcelize.parcelableCreator.
// import kotlinx.parcelize.parcelableCreator fun userFromParcel(parcel: Parcel): User { return parcelableCreator<User>().createFromParcel(parcel) }
Pomijanie właściwości podczas serializacji
Jeśli chcesz pominąć podział niektórych usług, użyj adnotacji @IgnoredOnParcel. Można jej też używać we właściwościach w treści klasy, aby wyciszyć ostrzeżenia o tym, że właściwość nie jest serializowana.
Właściwości konstruktora oznaczone adnotacją @IgnoredOnParcel muszą mieć wartość domyślną.
@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 }
Używanie metody android.os.Parcel.writeValue do serializacji właściwości
Możesz dodać do typu adnotację @RawValue, aby Parcelize używał Parcel.writeValue w przypadku tej właściwości.
@Parcelize class MyClass(val external: @RawValue ExternalClass) : Parcelable
Może to spowodować błąd w czasie działania, jeśli wartość właściwości nie jest natywnie obsługiwana przez Androida.
Parcelize może też wymagać użycia tej adnotacji, gdy nie ma innego sposobu serializacji właściwości.
Parcelizacja za pomocą klas i interfejsów zamkniętych
Parcelize wymaga, aby klasa do spakowania nie była abstrakcyjna. To ograniczenie nie dotyczy klas zamkniętych. Jeśli adnotacja @Parcelize jest używana w przypadku klasy zamkniętej, nie trzeba jej powtarzać w przypadku klas pochodnych.
@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
Konfigurowanie Parcelize dla Kotlin Multiplatform
funkcje będą znacznie ograniczone.Przed wprowadzeniem Kotlin 2.0 można było używać Parcelize, tworząc aliasy adnotacji Parcelize za pomocą expect i 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
W języku Kotlin w wersji 2.0 i nowszych aliasowanie adnotacji, które wywołują wtyczki, jest niedostępne. Aby to obejść, podaj nową adnotację Parcelize jako parametr additionalAnnotation wtyczki.
// 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
Interfejs Parcel jest dostępny tylko na Androidzie, więc Parcelize nie będzie generować kodu na innych platformach. Implementacje actual mogą być tam puste. Nie można też używać w kodzie wspólnym żadnych adnotacji, które wymagają odwoływania się do klasy Parcel, np. @WriteWith.
Funkcje eksperymentalne
Serializator klasy danych
Dostępne od wersji Kotlin 2.1.0.
Adnotacja DataClass umożliwia serializację klas danych tak, jakby były one same oznaczone adnotacją Parcelize. Ta adnotacja wymaga wyrażenia zgody na 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
Konstruktor podstawowy i wszystkie jego właściwości muszą być dostępne z klasy Parcelable. Dodatkowo wszystkie właściwości głównego konstruktora klasy danych muszą być obsługiwane przez Parcelize.
Jeśli wybrano opcję Custom Parcelers, należy ją określić w klasie Parcelable, a nie w klasie danych.
Jeśli klasa danych implementuje jednocześnie Serializable, adnotacja @DataClass jest ważniejsza: android.os.Parcel.writeSerializable nie będzie używana.
Praktycznym zastosowaniem tego rozwiązania jest serializacja kotlin.Pair.
Innym przydatnym przykładem jest uproszczenie kodu wieloplatformowego: kod wspólny może deklarować warstwę danych jako klasy danych, które kod Androida może następnie rozszerzyć o logikę serializacji, eliminując potrzebę stosowania w kodzie wspólnym adnotacji i aliasów typów specyficznych dla Androida.
// 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
Parametry inne niż val lub var w konstruktorze podstawowym
Dostępne od wersji Kotlin 2.1.0.
Aby włączyć tę funkcję, dodaj experimentalCodeGeneration=true do argumentów wtyczki parcelize.
kotlin {
compilerOptions {
// ...
freeCompilerArgs.addAll("-P", "plugin:org.jetbrains.kotlin.parcelize:experimentalCodeGeneration=true")
}
}
Ta funkcja znosi ograniczenie dotyczące argumentów konstruktora głównego, które muszą być typu val lub var. Rozwiązuje to jeden z problemów związanych z używaniem parcelize z dziedziczeniem, który wcześniej wymagał użycia właściwości 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)
Takie parametry mogą być używane tylko w argumentach konstruktora klasy bazowej. Nie można się do nich odwoływać w treści zajęć.
@Parcelize
class Derived(s: String): Base(s) { // allowed
@IgnoredOnParcel
val x: String = s // ERROR: not allowed.
init {
println(s) // ERROR: not allowed
}
}
Prześlij opinię
Jeśli napotkasz problemy z kotlin-parcelizewtyczką Gradle, możesz zgłosić błąd.