"التخطّي القوي" (Strong Skipping) هو وضع متاح في برنامج تجميع Compose. عند تفعيل هذا الخيار، يتم تغيير سلوك برنامج التجميع بطريقتَين:
- الدوال المركّبة التي تتضمّن مَعلمات غير ثابتة تصبح قابلة للتخطّي
- يتم تذكُّر دوال Lambda التي تتضمّن عمليات التقاط غير مستقرة
تفعيل وضع التخطّي القوي
يتم تفعيل ميزة "التخطّي القوي" تلقائيًا في الإصدار 2.0.20 من Kotlin.
لتفعيل ميزة "التخطّي القوي" لوحدة Gradle في إصدار أقدم من 2.0.20،
يُرجى تضمين الخيار التالي في
مجموعة composeCompiler من إعدادات Gradle:
android { ... }
composeCompiler {
enableStrongSkippingMode = true
}
إمكانية تخطّي الإعلانات القابلة للتجميع
يخفّف وضع التخطّي القوي بعض قواعد الثبات التي يطبّقها عادةً برنامج تجميع Compose في ما يتعلّق بالتخطّي والدوال المركّبة. بشكل تلقائي، يضع برنامج تجميع Compose علامة على دالة مركّبة بأنّها قابلة للتخطّي إذا كانت جميع وسيطاتها ذات قيم ثابتة. يغيّر وضع التخطّي القوي هذا السلوك.
عند تفعيل ميزة "التخطّي الفعّال"، تصبح جميع الدوال المركّبة القابلة لإعادة التشغيل قابلة للتخطّي. وينطبق ذلك سواء كانت المَعلمات غير مستقرة أم لا. تظل الدوال المركّبة غير القابلة لإعادة التشغيل غير قابلة للتخطّي.
متى يجب تخطّي الإعلان؟
لتحديد ما إذا كان سيتم تخطّي دالة مركّبة أثناء إعادة الإنشاء، تقارن أداة Compose قيمة كل مَعلمة بقيمها السابقة. يعتمد نوع المقارنة على ثبات المَعلمة.
- تتم مقارنة المَعلمات غير الثابتة باستخدام تساوي المثيلات (
===) - تتم مقارنة المَعلمات الثابتة باستخدام تساوي العناصر (
Object.equals())
إذا كانت جميع المَعلمات تستوفي هذه المتطلبات، تتخطّى أداة Compose الدالة المركّبة أثناء إعادة التركيب.
قد تحتاج إلى دالة مركّبة لإيقاف ميزة "التخطّي الفعّال". أي قد تحتاج إلى دالة مركّبة قابلة لإعادة التشغيل ولكن غير قابلة للتخطّي. في هذه الحالة، استخدِم التعليق التوضيحي @NonSkippableComposable.
@NonSkippableComposable
@Composable
fun MyNonSkippableComposable {}
إضافة تعليقات توضيحية إلى الفئات على أنّها ثابتة
إذا أردت مقارنة كائن باستخدام مساواة الكائن (Object.equals()) بدلاً من مساواة المثيل (===)، يمكنك مواصلة إضافة تعليقات توضيحية إلى الفئة المحدّدة باستخدام @Stable أو @Immutable.
يُرجى مراعاة المفاضلات التالية قبل إضافة @Stable أو @Immutable:
- الفئات ذات السمات الثابتة في وحدات Compose تكون ثابتة: يتم تلقائيًا استنتاج أنّ الفئة التي تحتوي على سمات
valمن الأنواع الثابتة في وحدة تم تجميعها باستخدام برنامج تجميع Compose هي ثابتة وتستخدم.equals()بدون الحاجة إلى@Immutableأو@Stable. - إضافة تعليقات توضيحية إلى الفئات التي تتضمّن عمليات تحقّق
.equals()منخفضة التكلفة فقط: يمكنك إضافة@Stableأو@Immutableعندما يتعذّر على برنامج التجميع استنتاج الثبات (مثل الفئات من وحدات غير Compose) ويتم تخصيص مثيلات جديدة بقيم متطابقة بشكل متكرر، بشرط أن تكون عملية التحقّق من.equals()للفئة منخفضة التكلفة. - يجب توخي الحذر عند إضافة تعليقات توضيحية إلى النماذج التي تحتوي على مجموعات: تؤدي إضافة
@Stableأو@Immutableإلى النماذج التي تحتوي على مجموعات (أو استبدالListبـImmutableList) إلى أن يقارن Compose كل عنصر في المجموعة باستخدام.equals()في كل عملية إعادة تركيب. بالنسبة إلى المجموعات أو النماذج الكبيرة المستخدَمة في التنسيقات الكسولة (LazyColumnأوLazyRowأوLazyGrid)، يمكن أن تكون مقارنة كل عنصر أبطأ من استخدام مساواة المثيلات (===) أو إعادة الإنشاء مباشرةً.
Lambda memoization
يتيح وضع التخطّي القوي أيضًا المزيد من الحفظ لدوال lambda داخل الدوال المركّبة. عند تفعيل ميزة "التخطّي القوي"، سيتم تلقائيًا تذكُّر كل دالة lambda داخل دالة مركّبة.
أمثلة
لتحقيق ميزة الحفظ في الذاكرة لدوال lambda داخل الدوال المركّبة عند استخدام ميزة التخطّي القوي،
يُغلِّف برنامج التجميع دالة lambda باستدعاء remember. ويتم ربطه بالمتغيّرات
التي تم التقاطها من دالة lambda.
لنفترض أنّ لديك دالة lambda كما في المثال التالي:
@Composable
fun MyComposable(unstableObject: Unstable, stableObject: Stable) {
val lambda = {
use(unstableObject)
use(stableObject)
}
}
عند تفعيل ميزة "التخطّي القوي"، يحفظ برنامج التجميع دالة lambda من خلال تضمينها في
استدعاء remember:
@Composable
fun MyComposable(unstableObject: Unstable, stableObject: Stable) {
val lambda = remember(unstableObject, stableObject) {
{
use(unstableObject)
use(stableObject)
}
}
}
تتّبع المفاتيح قواعد المقارنة نفسها التي تتّبعها الدوال المركّبة. تقارن بيئة التشغيل المفاتيح غير الثابتة باستخدام مساواة المثيلات. ويقارن بين المفاتيح الثابتة باستخدام مساواة العناصر.
التخزين المؤقت وإعادة الإنشاء
يؤدي هذا التحسين إلى زيادة كبيرة في عدد الدوال المركّبة التي يتخطّاها وقت التشغيل أثناء إعادة التركيب. بدون استخدام تقنية الحفظ، من المرجّح أن يخصّص وقت التشغيل دالة lambda جديدة لأي دالة مركّبة تأخذ مَعلمة lambda أثناء إعادة التركيب. ونتيجةً لذلك، يحتوي التعبير lambda الجديد على مَعلمات لا تساوي التركيب الأخير. يؤدي ذلك إلى إعادة الإنشاء.
تجنُّب التخزين المؤقت
إذا كان لديك دالة lambda لا تريد تخزينها مؤقتًا، استخدِم التعليق التوضيحي @DontMemoize.
val lambda = @DontMemoize {
...
}
حجم حزمة APK
عند تجميع الدوال المركّبة القابلة للتخطّي، ينتج عنها رمز برمجي أكثر من الدوال المركّبة غير القابلة للتخطّي. عند تفعيل ميزة "التخطّي الفعّال"، يضع برنامج التجميع علامة على جميع الدوال المركّبة تقريبًا على أنّها قابلة للتخطّي، ويغلّف جميع دوال lambda في remember{...}. لهذا السبب، فإنّ تفعيل وضع التخطّي القوي له تأثير صغير جدًا
على حجم حزمة APK لتطبيقك.
أدى تفعيل ميزة "التخطّي القوي" في تطبيق Now In Android إلى زيادة حجم حزمة APK بمقدار 4 كيلوبايت. يعتمد الفرق في الحجم إلى حد كبير على عدد الدوال المركّبة التي لم يكن من الممكن تخطّيها سابقًا والتي كانت موجودة في التطبيق المحدّد، ولكن يجب أن يكون بسيطًا نسبيًا.