الثبات في الإنشاء

يصنّف Compose الأنواع على أنّها ثابتة أو غير ثابتة. يكون النوع ثابتًا إذا كان غير قابل للتغيير، أو إذا كان بإمكان Compose معرفة ما إذا كانت قيمته قد تغيّرت بين عمليات إعادة الإنشاء. يكون النوع غير مستقر إذا لم يتمكّن Compose من معرفة ما إذا كانت قيمته قد تغيّرت بين عمليات إعادة الإنشاء.

تستخدم أداة Compose ثبات مَعلمات الدالة المركّبة لتحديد كيفية مقارنة المدخلات وتحديد ما إذا كان بإمكانها تخطّي الدالة المركّبة أثناء إعادة التركيب (مع تفعيل وضع التخطّي القوي تلقائيًا بدءًا من الإصدار 2.0.20 من Kotlin):

  • المَعلمات الثابتة: تقارن أداة Compose المَعلمات الثابتة باستخدام المساواة الهيكلية (Object.equals()). إذا كانت المَعلمات الثابتة للدالة المركّبة مساوية لقيمها السابقة، تتخطّاها أداة Compose.
  • المَعلمات غير الثابتة: عند تفعيل وضع التخطّي القوي (الوضع التلقائي في Kotlin 2.0.20 والإصدارات الأحدث)، تقارن أداة Compose المَعلمات غير الثابتة باستخدام تساوي المثيلات (===) وتتخطّى الدالة المركّبة إذا تم تمرير مثيلات الكائن نفسها. في الإصدارات السابقة من Kotlin 2.0.20 (أو عند إيقاف وضع التخطّي القوي)، يعيد Compose دائمًا تركيب دالة مركّبة باستخدام مَعلمات غير مستقرة عند إعادة تركيب الدالة الرئيسية.

إذا كان تطبيقك يخصّص بشكل متكرّر نُسخًا جديدة من المَعلمات غير الثابتة أو يفرض عمليات تحقّق .equals() مكلفة على مجموعات كبيرة من خلال الإفراط في إضافة التعليقات التوضيحية إلى النماذج، قد تلاحظ عمليات إعادة تركيب غير ضرورية أو عبء مقارنة.

يوضّح هذا المستند بالتفصيل كيفية تحديد Compose للثبات وكيفية تحسينه لتحسين الأداء وتجربة المستخدم بشكل عام.

العناصر غير القابلة للتغيير

توضّح المقتطفات التالية المبادئ العامة وراء الثبات وإعادة التركيب.

فئة Contact هي فئة بيانات غير قابلة للتغيير. وذلك لأنّ جميع مَعلماتها هي عناصر أساسية محدّدة باستخدام الكلمة الرئيسية val. بعد إنشاء مثيل من Contact، لا يمكنك تغيير قيمة خصائص الكائن. إذا حاولت القيام بذلك، فستقوم بإنشاء كائن جديد.

data class Contact(val name: String, val number: String)

تحتوي الدالة المركّبة ContactRow على مَعلمة من النوع Contact.

@Composable
fun ContactRow(contact: Contact, modifier: Modifier = Modifier) {
   var selected by remember { mutableStateOf(false) }

   Row(modifier) {
      ContactDetails(contact)
      ToggleButton(selected, onToggled = { selected = !selected })
   }
}

لنفترض أنّ المستخدم نقر على زر الإيقاف/التفعيل وتغيّرت الحالة selected:

  1. يقيّم Compose ما إذا كان عليه إعادة إنشاء الرمز داخل ContactRow.
  2. تلاحظ أنّ الوسيطة الوحيدة لـ ContactDetails هي من النوع Contact.
  3. بما أنّ Contact هي فئة بيانات غير قابلة للتغيير، يتأكّد Compose من عدم تغيير أي من وسيطات ContactDetails.
  4. وبالتالي، يتخطّى Compose دالة ContactDetails ولا يعيد إنشاءها.
  5. من ناحية أخرى، تغيّرت الوسيطات الخاصة بـ ToggleButton، ويعيد Compose إنشاء هذا المكوّن.

العناصر القابلة للتغيير

على الرغم من أنّ المثال السابق يستخدم كائنًا غير قابل للتغيير، من الممكن إنشاء كائن قابل للتغيير. لنفترض أنّ لدينا المقتطف التالي:

data class Contact(var name: String, var number: String)

بما أنّ كل مَعلمة من مَعلمات Contact أصبحت الآن var، لم تعُد الفئة غير قابلة للتغيير. إذا تغيّرت خصائصه، لن يتمكّن Compose من رصد ذلك. ذلك لأنّ Compose يتتبّع فقط التغييرات التي تطرأ على كائنات الحالة في Compose.

وتعتبر أداة Compose هذه الفئة غير مستقرة. باستخدام وضع التخطّي القوي (Kotlin 2.0.20+)، يقارن Compose بين Contact باستخدام مساواة المثيلات (===): لن يؤدي تغيير contact.name في مكانه إلى إعادة الإنشاء، بينما سيؤدي تمرير مثيل Contact مخصّص حديثًا بقيم متطابقة إلى فرض إعادة إنشاء ContactDetails (وبدون وضع التخطّي القوي، يتم إعادة إنشاء ContactDetails في كل مرة يتغير فيها selected).

التنفيذ في Compose

قد يكون من المفيد، ولكن ليس من الضروري، معرفة كيف تحدّد Compose الدوال التي يجب تخطّيها أثناء إعادة الإنشاء.

عندما يشغّل برنامج تجميع Compose الرمز البرمجي، يضع علامة على كل دالة ونوع باستخدام إحدى العلامات المتعددة. تعكس هذه العلامات كيفية تعامل Compose مع الدالة أو النوع أثناء إعادة الإنشاء.

الدوال

يمكن أن يضع Compose علامة على الدوال على أنّها skippable أو restartable. يُرجى العِلم أنّه قد يتم وضع علامة على دالة على أنّها واحدة من هاتين السمتَين أو كلتيهما أو لا شيء منهما:

  • قابلة للتخطّي: إذا وضع برنامج التجميع علامة على دالة مركّبة بأنّها قابلة للتخطّي، يمكن لأداة Compose تخطّيها أثناء إعادة الإنشاء إذا كانت جميع وسيطاتها مساوية لقيمها السابقة. (باستخدام وضع التخطّي القوي في الإصدار 2.0.20 من Kotlin والإصدارات الأحدث، يمكن تلقائيًا تخطّي جميع الدوال المركّبة القابلة لإعادة التشغيل).
  • قابل لإعادة التشغيل: تعمل الدالة المركّبة القابلة لإعادة التشغيل كـ "نطاق" يمكن أن تبدأ فيه عملية إعادة التركيب. بعبارة أخرى، يمكن أن تكون الدالة نقطة دخول يمكن من خلالها أن تبدأ Compose في إعادة تنفيذ الرمز لإعادة التركيب بعد تغييرات الحالة.

الأنواع

يصنّف Compose أنواع العلامات على أنّها غير قابلة للتغيير أو ثابتة. كل نوع هو واحد أو الآخر:

  • غير قابل للتغيير: يضع Compose علامة على نوع معيّن على أنّه غير قابل للتغيير إذا كانت قيمة خصائصه لا يمكن تغييرها مطلقًا وكانت جميع الطرق شفافة من الناحية المرجعية.
    • يُرجى العِلم أنّ جميع الأنواع الأساسية يتم وضع علامة عليها على أنّها غير قابلة للتغيير. وتشمل هذه المناطق: String وInt وFloat.
  • ثابت: يشير إلى نوع يمكن أن تتغيّر خصائصه بعد الإنشاء. وإذا تغيّرت هذه السمات أثناء وقت التشغيل، يصبح Compose على دراية بهذه التغييرات.

تصحيح أخطاء الثبات

إذا كان تطبيقك يعيد إنشاء دالة مركّبة لم تتغيّر مَعلماتها، عليك أولاً التحقّق مما إذا كان يتم تخصيص نُسخ جديدة من الأنواع غير الثابتة في كل عملية إعادة إنشاء (أو إذا كان وضع التخطّي القوي غير مفعّل، عليك التحقّق مما إذا كانت الدالة المركّبة تحتوي على مَعلمات تتضمّن سمات var أو سمات val من نوع غير ثابت).

للحصول على معلومات تفصيلية حول كيفية تشخيص المشاكل المعقّدة المتعلّقة بالثبات في Compose، يُرجى الاطّلاع على دليل تصحيح أخطاء الثبات.

حلّ مشاكل الثبات

للحصول على معلومات حول كيفية تحقيق الثبات في تنفيذ Compose، يُرجى الاطّلاع على دليل حلّ مشاكل الثبات.

ملخّص

بشكل عام، يجب مراعاة النقاط التالية:

  • المَعلمات: يحدّد Compose ثبات كل مَعلمة من مَعلمات الدوال المركّبة لتحديد ما إذا كان يجب مقارنتها باستخدام المساواة الهيكلية (.equals()) أو المساواة في المثيلات (===) أثناء إعادة الإنشاء.
  • الحلول الفورية: إذا لاحظت أنّه لا يتم تخطّي الدالة المركّبة وأنّ ذلك يؤدي إلى حدوث مشكلة في الأداء، تحقَّق مما إذا كان يتم إنشاء نُسخ جديدة من المَعلمات غير الثابتة في كل مرة أو ما إذا كان يتم استخدام سمات var بدلاً من State.
  • تقارير برنامج التجميع: يمكنك استخدام تقارير برنامج التجميع لتحديد الثبات الذي يتم استنتاجه بشأن فئاتك.
  • المجموعات: يعتبر Compose واجهات المجموعات العادية (List وSet وMap) غير مستقرة لأنّ عمليات التنفيذ الأساسية قد تكون قابلة للتغيير. باستخدام وضع التخطّي القوي (المفعَّل تلقائيًا في Kotlin 2.0.20 والإصدارات الأحدث)، تظل المجموعات غير الثابتة تتخطّى إعادة الإنشاء باستخدام مساواة المثيلات (===) عندما لا يتغيّر مرجع المجموعة. يُرجى توخي الحذر عند استبدال المجموعات العادية بمجموعات Kotlinx غير القابلة للتغيير أو إضافة تعليقات توضيحية إلى الفئات التي تحتوي على مجموعات باستخدام @Immutable أو @Stable، لأنّ مقارنة كل عنصر باستخدام .equals() في كل عملية إعادة تركيب يمكن أن تكون أكثر تكلفة من إعادة التركيب نفسها.
  • الوحدات الأخرى: يعتبر Compose الفئات من الوحدات التي لا يعمل فيها برنامج تجميع Compose غير مستقرة (تتم مقارنتها باستخدام === في وضع التخطّي القوي). إذا كان مصدر البيانات يعيد إنشاء نماذج صغيرة ومسطّحة بشكل متكرر من وحدات غير تابعة لـ Compose بقيم متطابقة، يمكنك ضبط ملف إعدادات الثبات أو استخدام @Stable أو @Immutable حيث تكون قيمة .equals() منخفضة.

محتوى إضافي للقراءة