افزونه kotlin-parcelize
یک مولد پیاده سازی Parcelable
را ارائه می دهد.
برای پشتیبانی از Parcelable
، افزونه Gradle را به فایل build.gradle
برنامه خود اضافه کنید:
شیار
plugins { id 'kotlin-parcelize' }
کاتلین
plugins { id("kotlin-parcelize") }
هنگامی که یک کلاس را با @Parcelize
حاشیه نویسی می کنید، یک پیاده سازی Parcelable
به طور خودکار ایجاد می شود، همانطور که در مثال زیر نشان داده شده است:
import kotlinx.parcelize.Parcelize
@Parcelize
class User(val firstName: String, val lastName: String, val age: Int): Parcelable
@Parcelize
نیاز دارد که تمام خصوصیات سریال در سازنده اولیه اعلان شوند. این افزونه یک هشدار در مورد هر ویژگی با یک فیلد پشتیبان اعلام شده در بدنه کلاس صادر می کند. همچنین، اگر برخی از پارامترهای سازنده اصلی ویژگی نباشند، نمیتوانید @Parcelize
اعمال کنید.
اگر کلاس شما به منطق سریال سازی پیشرفته تری نیاز دارد، آن را در یک کلاس همراه بنویسید:
@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
}
}
}
انواع پشتیبانی شده
@Parcelize
از طیف گسترده ای از انواع پشتیبانی می کند:
- انواع اولیه (و نسخه های جعبه ای آنها)
- اشیاء و شماره ها
-
String
،CharSequence
-
Duration
-
Exception
-
Size
,SizeF
,Bundle
,IBinder
,IInterface
,FileDescriptor
-
SparseArray
،SparseIntArray
،SparseLongArray
،SparseBooleanArray
- همه پیاده سازی های
Serializable
(از جملهDate
) وParcelable
- مجموعههایی از انواع پشتیبانیشده:
List
(نگاشت بهArrayList
)،Set
(نگاشت بهLinkedHashSet
)،Map
(نگاشت بهLinkedHashMap
)- همچنین تعدادی از پیاده سازی های مشخص:
ArrayList
،LinkedList
،SortedSet
،NavigableSet
،HashSet
،LinkedHashSet
،TreeSet
،SortedMap
،NavigableMap
،HashMap
،LinkedHashMap
،TreeMap
،ConcurrentHashMap
- همچنین تعدادی از پیاده سازی های مشخص:
- آرایه های همه انواع پشتیبانی شده
- نسخه های نول پذیر از همه انواع پشتیبانی شده
Parceler
سفارشی
اگر نوع شما مستقیماً پشتیبانی نمی شود، می توانید یک شی نگاشت Parceler
برای آن بنویسید.
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
یا @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
ایجاد داده از Parcel
در کد جاوا می توانید مستقیماً به فیلد CREATOR
دسترسی داشته باشید.
class UserCreator {
static User fromParcel(Parcel parcel) {
return User.CREATOR.createFromParcel(parcel);
}
}
در کاتلین نمی توانید مستقیماً از فیلد CREATOR
استفاده کنید. در عوض، از kotlinx.parcelize.parcelableCreator
استفاده کنید.
import kotlinx.parcelize.parcelableCreator
fun userFromParcel(parcel: Parcel): User {
return parcelableCreator<User>().createFromParcel(parcel)
}
پرش ویژگی ها از سریال سازی
اگر میخواهید برخی از اموال را از بستهبندی خودداری کنید، از حاشیهنویسی @IgnoredOnParcel
استفاده کنید. همچنین میتوان از آن در ویژگیهای داخل بدنه کلاس استفاده کرد تا هشدارهای مربوط به سریالی نشدن ویژگی را خاموش کند. ویژگی های سازنده حاشیه نویسی شده با @IgnoredOnParcel
باید یک مقدار پیش فرض داشته باشند.
@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 استفاده کنید
می توانید یک نوع را با @RawValue
حاشیه نویسی کنید تا Parcelize از Parcel.writeValue
برای آن ویژگی استفاده کند.
@Parcelize
class MyClass(val external: @RawValue ExternalClass): Parcelable
اگر مقدار ویژگی به طور بومی توسط Android پشتیبانی نشود، ممکن است در زمان اجرا شکست بخورد.
Parcelize همچنین ممکن است از شما بخواهد که از این حاشیه نویسی استفاده کنید، زمانی که هیچ راه دیگری برای سریال کردن دارایی وجود ندارد.
بسته بندی با کلاس های مهر و موم شده و رابط های مهر و موم شده
Parcelize به یک کلاس برای بسته بندی نیاز دارد تا انتزاعی نباشد. این محدودیت برای کلاس های مهر و موم شده اعمال نمی شود. هنگامی که حاشیه نویسی @Parcelize
در یک کلاس مهر و موم شده استفاده می شود، نیازی به تکرار برای کلاس های مشتق کننده نیست.
@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 برای چند پلتفرم Kotlin
قبل از Kotlin 2.0، میتوانید از Parcelize با نام مستعار حاشیهنویسی Parcelize با expect
و 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
در Kotlin 2.0 و بالاتر، نامگذاری حاشیه نویسی هایی که پلاگین ها را راه اندازی می کنند پشتیبانی نمی شود. برای دور زدن این موضوع، به جای آن یک حاشیه نویسی جدید Parcelize
به عنوان پارامتر 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
از آنجایی که رابط Parcel
فقط در اندروید در دسترس است، Parcelize هیچ کدی را روی پلتفرم های دیگر تولید نمی کند، بنابراین هر پیاده سازی actual
در آنجا خالی است. همچنین استفاده از هر حاشیهنویسی که نیاز به ارجاع به کلاس Parcel
دارد، برای مثال @WriteWith
، در کدهای رایج امکانپذیر نیست.
ویژگی های تجربی
سریال ساز کلاس داده
از Kotlin 2.1.0 در دسترس است.
حاشیه نویسی DataClass
اجازه می دهد تا کلاس های داده را به صورت سریالی تنظیم کنید که گویی خودشان با Parcelize
حاشیه نویسی شده اند. این حاشیه نویسی به گزینه 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
سازنده اولیه و تمام خصوصیات آن باید از کلاس Parcelable
قابل دسترسی باشند. علاوه بر این، تمام خصوصیات سازنده اصلی کلاس داده باید توسط Parcelize
پشتیبانی شوند. بستههای سفارشی ، در صورت انتخاب، باید در کلاس Parcelable
مشخص شوند، نه کلاس داده. اگر کلاس داده Serializable
همزمان اجرا کند، حاشیه نویسی @DataClass
اولویت دارد: android.os.Parcel.writeSerializable
استفاده نخواهد شد.
یک مورد کاربردی عملی برای این کار، سریال سازی kotlin.Pair
است. مثال مفید دیگر سادهسازی کد چند پلتفرمی است: کدهای رایج میتوانند لایه داده را به عنوان کلاسهای داده معرفی کنند، که کد اندروید میتواند آن را با منطق سریالسازی تقویت کند و نیاز به حاشیهنویسی خاص اندروید و نام مستعار در کدهای رایج را از بین ببرد.
// 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
پارامترهای غیر val یا var در سازنده اولیه
از Kotlin 2.1.0 در دسترس است.
برای فعال کردن این ویژگی، experimentalCodeGeneration=true
را به آرگومانهای پلاگین parcelize اضافه کنید.
kotlin {
compilerOptions {
// ...
freeCompilerArgs.addAll("-P", "plugin:org.jetbrains.kotlin.parcelize:experimentalCodeGeneration=true")
}
}
این ویژگی محدودیت را بر روی آرگومان های سازنده اصلی که باید val
یا var
باشند، برطرف می کند. این یک نقطه درد استفاده از parcelize با ارث را حل می کند، که قبلاً به استفاده از ویژگی های 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)
چنین پارامترهایی فقط مجاز به استفاده در آرگومان های سازنده کلاس پایه هستند. ارجاع آنها در بدنه کلاس مجاز نیست.
@Parcelize
class Derived(s: String): Base(s) { // allowed
@IgnoredOnParcel
val x: String = s // ERROR: not allowed.
init {
println(s) // ERROR: not allowed
}
}
بازخورد
اگر با پلاگین kotlin-parcelize
Gradle با مشکلی مواجه شدید، می توانید یک اشکال را ثبت کنید .