يوفّر المكوّن الإضافي kotlin-parcelize
أداة إنشاء ملف تنفيذ
Parcelable
.
لتضمين ميزة التوافق مع Parcelable
، أضِف المكوّن الإضافي Gradle إلىملفbuild.gradle
في
تطبيقك:
رائع
plugins { id 'kotlin-parcelize' }
Kotlin
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
في رمز 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 من خلال إنشاء أسماء بديلة للتعليقات التوضيحية في 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
في الإصدار 2.0 من 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
.
يجب تحديد مقدّمي الطرود، في حال اختيارهم، في
الفئة 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
إلى وسيطات المكوّن الإضافي المقسّمة.
kotlin {
compilerOptions {
// ...
freeCompilerArgs.addAll("-P", "plugin:org.jetbrains.kotlin.parcelize:experimentalCodeGeneration=true")
}
}
تزيل هذه الميزة القيود المفروضة على وسيطات الدالة الإنشائية الأساسية التي يجب أن تكون
val
أو var
. يحلّ هذا الأمر إحدى المشاكل المتعلقة باستخدام ميزة "تقسيم المنتج" مع الميزة "الاستبدال الوراثي"،
التي كانت تتطلّب في السابق استخدام سمات 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، يمكنك
إبلاغنا بالخطأ.