تطوير Android / الأساسي: أسس Android وCompose / الدرس 4
حالة Compose والأحداث وإعادة التركيب
ابنِ عنوان قراءة قابلاً للتحرير بإظهار ملكية الحالة وفصل العرض عن الآثار الجانبية.
في هذه الصفحة
أهداف الدرس
- اشرح إعادة التركيب ومراقبة الحالة.
- ارفع الحالة واختر لها عمراً مناسباً.
صِف الواجهة انطلاقاً من القيم الحالية
تصف الدالة التركيبية الواجهة لمدخلاتها الحالية. عندما تتغير حالة مراقبة يستطيع Compose إعادة تنفيذ الدوال المتأثرة وتحديث التركيب. قد تحدث إعادة التركيب كثيراً وقد تتجاوز بعض الدوال، ولا تضمن تنفيذ كل تعليمة مرة واحدة. لذلك لا ينبغي لجسم الدالة إرسال طلبات أو كتابة ملفات أو زيادة عداد عام لمجرد عرضه. اعتبر الشاشة إسقاطاً للحالة وإيماءات المستخدم أحداثاً تطلب من مالكها إنتاج حالة جديدة.
اجعل الحالة المحلية القابلة للتحرير مراقبة
يعاد إنشاء المتغير المحلي العادي عند تنفيذ دالته ولا يخطر Compose عند الإسناد إليه. يحتفظ remember بكائن ما دام استدعاؤه في التركيب، ويجعل mutableStateOf القراءات قابلة للمراقبة. يحفظ rememberSaveable أيضاً القيم الصغيرة المؤهلة بآلية الحالة المحفوظة. يفيد ذلك لمسودة نص، لكنه لا يعوض قاعدة البيانات ولا يضمن الاسترداد بعد كل أشكال الإنهاء. يختفي الكائن المتذكر عندما يغادر مالكه التركيب؛ لذلك اختيار المالك مهم بقدر اختيار واجهة الحالة.
@Composable
fun TitleEditor() {
var title by rememberSaveable { mutableStateOf("") }
TitleField(title = title, onTitleChange = { title = it })
}
استخدم استيرادي getValue وsetValue من Compose runtime، وmutableStateOf وrememberSaveable ضمن مشروع Compose المولّد. تُعرّف TitleField أدناه. تصمد هذه الحالة أمام الاستعادة المدعومة للحالة المحفوظة، لكن السجلات المؤكدة تبقى مسؤولية التخزين الدائم.
اكشف القيم والأحداث
يرفع نقل الحالة القيمة إلى أقرب مالك مشترك يحتاج قراءتها أو تعديلها. يتلقى الحقل القابل لإعادة الاستخدام نصه الحالي ودالة onTitleChange بدلاً من إنشاء نسخة خاصة ثانية. يستطيع الأب عندئذ التحقق من القيمة أو حفظها أو مشاركتها مع معاينة. ينشئ ذلك اتجاهاً واحداً: تنزل القيم وتصعد الأحداث. تجنب تمرير متحكم شاشة كامل لكل عنصر صغير؛ تجعل دالة رد محدودة المكوّن أسهل للمعاينة والاختبار دون نشاط حقيقي أو طبقة بيانات.
@Composable
fun TitleField(title: String, onTitleChange: (String) -> Unit) {
OutlinedTextField(
value = title,
onValueChange = onTitleChange,
label = { Text(stringResource(R.string.reading_title)) },
singleLine = true
)
}
أضف reading_title إلى موارد النصوص واستورد مكونات Material وstringResource. يظل الأب مصدر الحقيقة. يبلغ الحقل عن النص المقترح بدلاً من تعديل نموذج دون علم الأب.
امنح الآثار أعماراً صريحة
الأثر عمل مرتبط بالتركيب أو دورة الحياة بدلاً من وصف الواجهة. يبدأ LaunchedEffect coroutine عند دخوله التركيب ويعيد تشغيلها عند تغير مفاتيحه. يقرن DisposableEffect التسجيل بالتنظيف. اختر مفاتيح تمثل هوية العمل كمعرّف عنصر، لا قيمة عشوائية تتغير مع كل عرض. حفظ السجل عادة حدث مستخدم يعالجه مالك الحالة وليس نتيجة تلقائية لعرض عنوانه. تحتاج العمليات الدائمة ملكية أقوى من دالة تركيبية قد تختفي.
انشر التغييرات بدلاً من إخفاء التعديل
يجب أن يراقب Compose الحالة المتغيرة. قد يترك تعديل MutableList عادية داخل حاوية متذكرة القراء دون إخطار؛ استبدل قائمة ثابتة الاستخدام أو استخدم مجموعة تراعي لقطات الحالة بقصد. احسب القيم المشتقة البسيطة مباشرة من المدخلات، وخصص derivedStateOf للحالات التي يقلل فيها تحديثات غير لازمة. أبعد العمل المكلف عن مسار العرض. عند المراجعة اسأل: أي قراءة حالة تحفز هذه الواجهة، وأي حدث يغيرها؟ إذا غاب الجواب فالعقد يحتاج عناية قبل إضافة آثار أخرى.
الأخطاء الشائعة وإصلاحها
لا تحدّث الكتابة الحقل
- لماذا يحدث؟
- يُخزن النص في متغير عادي أو نسخة منفصلة.
- كيف تصلحه؟
- استخدم حالة مراقبة يملكها الأب وأعد تمرير قيمتها.
- كيف تتجنب تكراره؟
- تتبّع دورة القيمة والحدث والقيمة كاملة عند المراجعة.
يتكرر طلب مع كل عرض
- لماذا يحدث؟
- تعمل الآثار الجانبية مباشرة داخل جسم الدالة التركيبية.
- كيف تصلحه؟
- انقل العمل إلى معالج حدث أو أثر بمفتاح صحيح.
- كيف تتجنب تكراره؟
- أبقِ دوال العرض خالية من التعديل الخارجي غير المنضبط.
تختفي المسودة عند تبديل الشاشات
- لماذا يحدث؟
- غادر مالكها المتذكر التركيب.
- كيف تصلحه؟
- انقل الملكية إلى حاوية حالة الشاشة المناسبة أو مخزن مسودة دائم.
- كيف تتجنب تكراره؟
- دوّن العمر المطلوب قبل اختيار الواجهة.
اختبر فهمك
1. يحرر عنصران شقيقان العنوان نفسه ويعاينانه. أين يعيش العنوان وماذا يتلقى كل ابن؟
اعرض الحل المشروح
احتفظ بعنوان واحد لدى أقرب مالك مشترك. أعط المحرر القيمة ودالة تحديث، وأعط المعاينة القيمة فقط. لا تحتاج المعاينة صلاحية التعديل. يمكن اشتقاق رسالة التحقق من العنوان نفسه كي تتفق الأجزاء الثلاثة فور كل حدث.
2. يستخدم أثر تحميل الوقت الحالي مفتاحاً له. اشرح الفشل واختر مفتاحاً أفضل.
اعرض الحل المشروح
يتغير المفتاح بين العروض فيُلغى العمل ويعاد تشغيله مراراً. استخدم معرّف العنصر الثابت عندما يرتبط التحميل به، وانقل تحميل الأعمال إلى حاوية حالة الشاشة إذا لزم صموده أمام تغير التركيب. يجب أن يظل الإلغاء تعاونياً وألا يعامل كفشل عادي.
أهم ما تعلمته
- تحدد ملكية الحالة الاتساق والعمر معاً.
- تصبح إعادة التركيب آمنة عندما يكون العرض متوقعاً.
- تطلب الأحداث التغييرات وتحتاج العناصر القابلة لإعادة الاستخدام عقوداً محدودة.