يوفّر المكوّن الإضافي 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،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
- يتضمّن هذا النوع أيضًا عددًا من عمليات التنفيذ المحدّدة:
- مصفوفات من جميع الأنواع المتوافقة
- إصدارات تقبل القيم الخالية من جميع الأنواع المتوافقة
Parcelers مخصّصة
إذا لم يكن نوعك متوافقًا بشكل مباشر، يمكنك كتابة 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 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 المتعدّدة
قبل الإصدار 2.0 من Kotlin، كان بإمكانك استخدام 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، في الرمز البرمجي المشترك.
الميزات التجريبية
أداة نشر فئة البيانات على نحو متسلسِل
تتوفّر هذه الميزة منذ الإصدار 2.1.0 من Kotlin.
تسمح التعليق التوضيحي 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 في الدالة الإنشائية الأساسية
تتوفّر هذه الميزة منذ الإصدار 2.1.0 من Kotlin.
لتفعيل هذه الميزة، أضِف 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 plugin، يمكنك
تسجيل خطأ.