يوفّر المكوّن الإضافي 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
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
إلى مَعلمات الإضافة parcelize.
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، يمكنك
إبلاغنا بالخطأ.