إصلاح مشاكل الثبات

عندما تواجه فئة غير مستقرة تسبب مشاكل في الأداء، يجب أن تجعلها مستقرة. يوضح هذا المستند العديد من الأساليب التي يمكنك استخدامها للقيام بذلك.

جعل الصف غير قابل للتغيير

يجب أن تحاول أولاً جعل فئة غير مستقرة غير قابلة للتغيير تمامًا.

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

المجموعات غير القابلة للتغيير

تُعدّ المجموعات أحد الأسباب الشائعة وراء اعتبار ميزة Compose فئة غير مستقرة. كما ورد في صفحة تشخيص مشاكل استقرار الأداء، لا يمكن لبرنامج التجميع البرمجي Compose التأكد تمامًا من أنّ المجموعات مثل List, Map وSet غير قابلة للتغيير بالتأكيد، وبالتالي فهي غير مستقرة.

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

جرّب مرة أخرى هذه الفئة غير المستقرة من دليل تشخيص مشاكل الاستقرار:

unstable class Snack {
  …
  unstable val tags: Set<String>
  …
}

يمكنك جعل tags ثابتة باستخدام مجموعة غير قابلة للتغيير. في الصف، غيِّر نوع tags إلى ImmutableSet<String>:

data class Snack{
    …
    val tags: ImmutableSet<String> = persistentSetOf()
    …
}

وبعد القيام بذلك، تصبح جميع معاملات الفئة غير قابلة للتغيير، ويضع برنامج التجميع Compose علامة على الفئة على أنها مستقرة.

إضافة تعليقات توضيحية باستخدام Stable أو Immutable

هناك مسار محتمل لحلّ مشاكل الاستقرار من خلال إضافة تعليقات توضيحية إلى الفئات غير الثابتة باستخدام @Stable أو @Immutable.

إنّ إضافة التعليقات التوضيحية إلى فئة تتجاوز ما يستنتجه المحول البرمجي في ما يتعلق بالصف. وهو يشبه عامل التشغيل !! في Kotlin. يجب أن تكون حريصًا للغاية بشأن كيفية استخدام هذه التعليقات التوضيحية. قد يؤدي تجاوز سلوك برنامج التجميع إلى حدوث أخطاء غير متوقعة، كعدم إعادة إنشاء المحتوى الذي يتوقعه المستخدم.

فإذا كان من الممكن جعل فئتك مستقرة بدون تعليق توضيحي، فيجب أن تسعى جاهدًا لتحقيق الاستقرار بهذه الطريقة.

يقدم المقتطف التالي مثالاً بسيطًا لفئة بيانات تم التعليق عليها على أنها غير قابلة للتغيير:

@Immutable
data class Snack(
…
)

سواء كنت تستخدم التعليق التوضيحي @Immutable أو @Stable، يضع المحول البرمجي Compose علامة على الفئة Snack على أنّها ثابتة.

الصفوف التي تتضمّن تعليقات توضيحية في المجموعات

يجب مراعاة مادة مركّبة تتضمن معلَمة من النوع List<Snack>:

restartable scheme("[androidx.compose.ui.UiComposable]") fun HighlightedSnacks(
  …
  unstable snacks: List<Snack>
  …
)

حتى إذا أضفت تعليقًا توضيحيًا إلى Snack باستخدام @Immutable، سيظل المحول البرمجي لإنشاء الإشارة إلى المعلمة snacks في HighlightedSnacks غير مستقر.

تواجه المعلمات المشكلة نفسها التي تواجهها الفئات عندما يتعلق الأمر بأنواع المجموعات، يضع برنامج التجميع في Compose دائمًا علامة على مَعلمة من النوع List على أنّها غير مستقرة، حتى عندما تكون مجموعة من الأنواع الثابتة.

لا يمكنك وضع علامة على معلمة فردية كثابتة، ولا يمكنك إضافة تعليقات توضيحية إلى عنصر قابل للتخطي دائمًا. هناك عدة مسارات للتقديم.

هناك عدة طرق يمكنك من خلالها التغلب على مشكلة المجموعات غير المستقرة. توضّح الأقسام الفرعية التالية هذه الأساليب المختلفة.

ملف الإعداد

إذا كنت تريد الالتزام بعقد الاستقرار في قاعدة الترميز، يمكنك الموافقة على اعتبار مجموعات Kotlin مستقرة من خلال إضافة kotlin.collections.* إلى ملف إعداد الثبات.

مجموعة غير قابلة للتغيير

لتوفير سلامة وقت تجميع البيانات غير القابلة للتغيير، يمكنك استخدام مجموعة kotlinx غير القابلة للتغيير بدلاً من List.

@Composable
private fun HighlightedSnacks(
    …
    snacks: ImmutableList<Snack>,
    …
)

Wrapper

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

@Immutable
data class SnackCollection(
   val snacks: List<Snack>
)

يمكنك بعد ذلك استخدام هذا كنوع المعلمة في العنصر القابل للإنشاء.

@Composable
private fun HighlightedSnacks(
    index: Int,
    snacks: SnackCollection,
    onSnackClick: (Long) -> Unit,
    modifier: Modifier = Modifier
)

الحل

بعد اتّباع أي من هاتين الطريقتين، أصبح برنامج التجميع في Compose يضع علامة على HighlightedSnacks Composable على أنّها skippable وrestartable معًا.

restartable skippable scheme("[androidx.compose.ui.UiComposable]") fun HighlightedSnacks(
  stable index: Int
  stable snacks: ImmutableList<Snack>
  stable onSnackClick: Function1<Long, Unit>
  stable modifier: Modifier? = @static Companion
)

أثناء إعادة الإنشاء، يمكن الآن لميزة Compose تخطي HighlightedSnacks في حال لم يتغيّر أي من إدخالاتها.

ملف إعداد الثبات

بدءًا من Compose Compiler 1.5.5، يمكن توفير ملف تهيئة للفئات التي تعد مستقرة في وقت التجميع. ويتيح هذا الإجراء اعتبار الفئات التي لا تتحكم فيها، مثل فئات المكتبة العادية مثل LocalDateTime، كفئات مستقرة.

ملف الإعداد هو ملف نصي عادي يحتوي على فئة واحدة في كل صف. ويمكن استخدام التعليقات وأحرف البدل الفردية والمزدوجة. في ما يلي مثال على عملية الضبط:

// Consider LocalDateTime stable
java.time.LocalDateTime
// Consider kotlin collections stable
kotlin.collections.*
// Consider my datalayer and all submodules stable
com.datalayer.**
// Consider my generic type stable based off it's first type parameter only
com.example.GenericClass<*,_>

لتمكين هذه الميزة، مرر مسار ملف التهيئة إلى خيارات أداة التحويل البرمجي لإنشاء الإنشاء.

رائع

kotlinOptions {
    freeCompilerArgs += [
            "-P",
            "plugin:androidx.compose.compiler.plugins.kotlin:stabilityConfigurationPath=" +
                    project.absolutePath + "/compose_compiler_config.conf"
    ]
}

Kotlin

kotlinOptions {
  freeCompilerArgs += listOf(
      "-P",
      "plugin:androidx.compose.compiler.plugins.kotlin:stabilityConfigurationPath=" +
      "${project.absolutePath}/compose_compiler_config.conf"
  )
}

نظرًا لأن برنامج Compose المحول البرمجي يعمل على كل وحدة في المشروع بشكل منفصل، يمكنك توفير تكوينات مختلفة لوحدات مختلفة إذا لزم الأمر. بدلاً من ذلك، يمكنك استخدام إعداد واحد على مستوى الجذر لمشروعك وتمرير هذا المسار إلى كل وحدة.

وحدات متعددة

وهناك مشكلة شائعة أخرى تتعلق بالبنية متعددة الوحدات. لا يمكن لبرنامج التجميع البرمجي Compose استنتاج ما إذا كانت الفئة مستقرة فقط إذا كانت جميع الأنواع غير الأولية التي تشير إليها إما ثابتة أو في وحدة تم إنشاؤها أيضًا باستخدام المحول البرمجي Compose.

إذا كانت طبقة البيانات في وحدة منفصلة عن طبقة واجهة المستخدم، وهو الأسلوب الموصى به، فقد تكون هذه مشكلة تواجهها.

الحل

لحل هذه المشكلة، يمكنك اتّباع أحد الأساليب التالية:

  1. أضِف الفئات إلى ملف إعداد Compiler.
  2. ويمكنك تفعيل برنامج Compose المحول البرمجي في وحدات طبقة البيانات، أو وضع علامة على الفئات باستخدام @Stable أو @Immutable متى كان ذلك مناسبًا.
    • يتضمن هذا إضافة تبعية إنشاء إلى طبقة البيانات الخاصة بك. ومع ذلك، إنها مجرد التبعية لوقت تشغيل Compose وليس لـ Compose-UI.
  3. ضمن وحدة واجهة المستخدم، يمكنك إحاطة فئات طبقة البيانات بفئات برامج تضمين خاصة بواجهة المستخدم.

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

ليس من الضروري أن تكون جميع المواد الإبداعية قابلة للتخطي

وعند العمل على إصلاح المشاكل المتعلقة بالثبات، لا يجوز أن تحاول جعل كل العناصر التي تم إنشاؤها قابلة للتخطي. ويمكن أن تؤدي محاولة تنفيذ ذلك إلى تحسين سابق يعرض مشاكل أكثر مما يمكن حلها.

هناك العديد من المواقف التي لا يجني فيها الإعلانات القابلة للتخطي أي فائدة حقيقية، ويمكن أن تؤدي إلى صعوبة في صيانتها. مثلاً:

  • مادة قابلة مركّبة لا تتم إعادة تركيبها في كثير من الأحيان أو لا تتم إعادة تركيبها على الإطلاق.
  • مادة قابلة للتخطي تُسمى في حد ذاتها مواد قابلة للتخطي.
  • يمكن تركيبه بعدد كبير من المعلمات مع عمليات تنفيذ باهظة الثمن. في هذه الحالة، يمكن أن تفوق تكلفة التحقق مما إذا كان أي معلمة قد تغيرت تكلفة إعادة التركيب رخيصة.

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