افزایه 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،CharSequenceDurationExceptionSize،SizeF،Bundle،IBinder،IInterface،FileDescriptorSparseArray،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
در کد Java، میتوانید مستقیماً به فیلد CREATOR دسترسی داشته باشید.
class UserCreator {
static User fromParcel(Parcel parcel) {
return User.CREATOR.createFromParcel(parcel);
}
}
در Kotlin، نمیتوانید مستقیماً از فیلد 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 ازطریق expect و actual از Parcelize استفاده کنید:
// 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 نسخه ۲.۰ و بالاتر، نام مستعار حاشیهنویسیهایی که افزایهها را راهاندازی میکنند پشتیبانی نمیشود. برای دور زدن این محدودیت، بهجای آن، یک
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 فقط در Android دردسترس است، 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 پشتیبانی شود.
اگر Custom Parcelers انتخاب شده باشد، باید در کلاس
Parcelable مشخص شود، نه در کلاس داده.
اگر کلاس داده بهطور همزمان Serializable را پیادهسازی کند، اولویت با گزارمان @DataClass
است:
android.os.Parcel.writeSerializable
استفاده نخواهد شد.
یک مورد استفاده عملی برای این کار، سریالسازی kotlin.Pair است.
مثال مفید دیگر سادهسازی کد چندسکویی است:
کد مشترک میتواند لایه داده را بهعنوان کلاسهای داده تعریف کند، که کد Android
میتواند آن را با منطق سریالسازی تکمیل کند و نیاز به
نامگذاریهای خاص Android و نامهای مستعار نوع در کد مشترک را برطرف کند.
// 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 مشکلی داشتید، میتوانید
گزارش اشکال ثبت کنید.