kotlin-parcelize
eklentisi, Parcelable
uygulama oluşturucu sağlar.
Parcelable
desteğini dahil etmek için Gradle eklentisini uygulamanızın build.gradle
dosyasına ekleyin:
Groovy
plugins { id 'kotlin-parcelize' }
Kotlin
plugins { id("kotlin-parcelize") }
Bir sınıfa @Parcelize
kodunu eklediğinizde, aşağıdaki örnekte gösterildiği gibi otomatik olarak bir Parcelable
uygulaması oluşturulur:
import kotlinx.parcelize.Parcelize
@Parcelize
class User(val firstName: String, val lastName: String, val age: Int): Parcelable
@Parcelize
, tüm serileştirilmiş özelliklerin birincil oluşturucuda tanımlanmasını gerektirir. Eklenti, sınıf gövdesinde tanımlanmış bir destek alanı içeren her mülk için uyarı verir. Ayrıca, birincil kurucu parametrelerinden bazıları özellik değilse @Parcelize
'ü uygulayamazsınız.
Sınıfınız için daha gelişmiş bir serileştirme mantığı gerekiyorsa bunu bir tamamlayıcı sınıfın içine yazın:
@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
}
}
}
Desteklenen türler
@Parcelize
çok çeşitli türleri destekler:
- Temel türler (ve kutulu sürümleri)
- Nesneler ve enum'lar
String
,CharSequence
Duration
Exception
Size
,SizeF
,Bundle
,IBinder
,IInterface
,FileDescriptor
SparseArray
,SparseIntArray
,SparseLongArray
,SparseBooleanArray
- Tüm
Serializable
(Date
dahil) veParcelable
uygulamaları - Desteklenen tüm türlerin koleksiyonları:
List
(ArrayList
ile eşlenir),Set
(LinkedHashSet
ile eşlenir),Map
(LinkedHashMap
ile eşlenir)- Ayrıca bazı somut uygulamalar:
ArrayList
,LinkedList
,SortedSet
,NavigableSet
,HashSet
,LinkedHashSet
,TreeSet
,SortedMap
,NavigableMap
,HashMap
,LinkedHashMap
,TreeMap
,ConcurrentHashMap
- Ayrıca bazı somut uygulamalar:
- Desteklenen tüm türlerin dizileri
- Desteklenen tüm türlerin boş değerli sürümleri
Özel Parceler
'ler
Türünüz doğrudan desteklenmiyorsa bunun için bir Parceler
eşleme nesnesi yazabilirsiniz.
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)
}
}
@TypeParceler
veya @WriteWith
ek açıklamalarını kullanarak harici paketleyiciler uygulayabilirsiniz:
// 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
Paketten veri oluşturma
Java kodunda, CREATOR
alanına doğrudan erişebilirsiniz.
class UserCreator {
static User fromParcel(Parcel parcel) {
return User.CREATOR.createFromParcel(parcel);
}
}
Kotlin'de CREATOR
alanını doğrudan kullanamazsınız. Bunun yerine kotlinx.parcelize.parcelableCreator
kullanın.
import kotlinx.parcelize.parcelableCreator
fun userFromParcel(parcel: Parcel): User {
return parcelableCreator<User>().createFromParcel(parcel)
}
Özellikleri serileştirmeden atlama
Bazı mülkleri parsellemeye dahil etmek istemiyorsanız @IgnoredOnParcel
ek açıklamasını kullanın. Ayrıca, sınıfın gövdesindeki mülklerde, mülkün serileştirilmediğiyle ilgili uyarıları devre dışı bırakmak için de kullanılabilir.
@IgnoredOnParcel
ile ek açıklama eklenmiş kurucu özellikleri varsayılan bir değere sahip olmalıdır.
@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
}
Bir mülkü seri hale getirmek için android.os.Parcel.WriteValue kullanın
Bir türün üzerine @RawValue
ekleyerek Parcelize'in söz konusu mülk için Parcel.writeValue
kullanmasını sağlayabilirsiniz.
@Parcelize
class MyClass(val external: @RawValue ExternalClass): Parcelable
Özelliğin değeri Android tarafından yerel olarak desteklenmiyorsa bu işlem çalışma zamanında başarısız olabilir.
Parçalara ayırma işlemi, mülkü serileştirmenin başka bir yolu olmadığında bu ek açıklamayı kullanmanızı da gerektirebilir.
Mühürlü sınıflar ve mühürlü arayüzler ile paketleme
Paketleme işlemi için, paketlenecek sınıfın soyut olmaması gerekir. Bu sınırlama, mühürlü sınıflar için geçerli değildir. @Parcelize
ek açıklaması mühürlü bir sınıfta kullanıldığında, türetme sınıfları için tekrarlanması gerekmez.
@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
Kotlin çok platformlu için Parcelize'i ayarlama
Kotlin 2.0'dan önce, Parcelize ek açıklamalarını expect
ve actual
ile takma adlandırarak Parcelize'i kullanabiliyordunuz:
// 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
Kotlin 2.0 ve sonraki sürümlerde, eklentileri tetikleyen takma ad ek açıklamaları desteklenmez. Bunu atlatmak için eklentiye additionalAnnotation
parametresi olarak yeni bir Parcelize
ek açıklaması sağlayın.
// 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
Parcel
arayüzü yalnızca Android'de kullanılabildiğinden Parcelize diğer platformlarda kod oluşturmaz. Bu nedenle, bu platformlardaki actual
uygulamaları boş olabilir. Ayrıca, ortak kodda Parcel
sınıfına referans vermeyi gerektiren ek açıklamaların (ör. @WriteWith
) kullanılması da mümkün değildir.
Deneysel özellikler
Veri sınıfı serileştirici
Kotlin 2.1.0'dan beri kullanılabilir.
DataClass
ek açıklama, veri sınıflarının Parcelize
ile ek açıklama yapılmış gibi serileştirilmesine olanak tanır. Bu ek açıklama için kotlinx.parcelize.Experimental
etkinleştirmesi gerekir.
@file:OptIn(kotlinx.parcelize.Experimental::class)
data class C(val a: Int, val b: String)
@Parcelize
class P(val c: @DataClass C) : Parcelable
Birincil oluşturucuya ve tüm özelliklerine Parcelable
sınıfından erişilebilmelidir. Buna ek olarak, veri sınıfının tüm birincil oluşturucu özellikleri Parcelize
tarafından desteklenmelidir.
Seçilen özel paketleyiciler, veri sınıfında değil Parcelable
sınıfında belirtilmelidir.
Veri sınıfı aynı anda Serializable
uygularsa @DataClass
ek açıklama öncelikli olur:
android.os.Parcel.writeSerializable
kullanılmaz.
Bunun pratik bir kullanım alanı, kotlin.Pair
öğesini serileştirmek olabilir.
Yararlı bir örnek de çoklu platform kodunun basitleştirilmesidir: Ortak kod, veri katmanını veri sınıfları olarak tanımlayabilir. Android kodu daha sonra bu sınıfları serileştirme mantığıyla genişletebilir. Böylece, ortak kodda Android'e özgü ek açıklamalara ve tür takma adlarına gerek kalmaz.
// 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
Birincil kurucuda val veya var olmayan parametreler
Kotlin 2.1.0'dan beri kullanılabilir.
Bu özelliği etkinleştirmek için parcelize eklenti bağımsız değişkenlerine experimentalCodeGeneration=true
ekleyin.
kotlin {
compilerOptions {
// ...
freeCompilerArgs.addAll("-P", "plugin:org.jetbrains.kotlin.parcelize:experimentalCodeGeneration=true")
}
}
Bu özellik, val
veya var
olması gereken birincil kurucu bağımsız değişkenlerindeki kısıtlamayı kaldırır. Bu, daha önce open
özelliklerinin kullanılmasını gerektiren, devralma ile parcelize kullanmanın bir sorununu çözer.
// 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)
Bu tür parametrelerin yalnızca temel sınıf kurucusunun bağımsız değişkenlerinde kullanılmasına izin verilir. Sınıfın gövdesinde bunlara referans verilmesine izin verilmez.
@Parcelize
class Derived(s: String): Base(s) { // allowed
@IgnoredOnParcel
val x: String = s // ERROR: not allowed.
init {
println(s) // ERROR: not allowed
}
}
Geri bildirim
kotlin-parcelize
Gradle eklentisiyle ilgili herhangi bir sorunla karşılaşırsanız hata kaydı oluşturabilirsiniz.