المفاهيم وتنفيذ Jetpack Compose
يمكن أن تتغيّر بعض إعدادات الجهاز أثناء تشغيل التطبيق. وتشمل هذه الإعدادات على سبيل المثال لا الحصر ما يلي:
- حجم عرض التطبيق
- اتجاه الشاشة
- حجم الخط وعرضه
- اللغة
- الوضع الداكن مقابل الوضع الفاتح
- مدى توفّر لوحة المفاتيح
تحدث معظم تغييرات الإعدادات هذه بسبب تفاعل المستخدم. على
سبيل المثال، يؤدي تدوير الجهاز أو طيّه إلى تغيير مساحة الشاشة
المتاحة لتطبيقك. وبالمثل، يؤدي تغيير إعدادات الجهاز، مثل حجم الخط،
أو اللغة أو المظهر المفضّل، إلى تغيير القيم المقابلة لها في
Configuration عنصر.
تتطلب هذه المَعلمات عادةً تغييرات كبيرة بما يكفي في واجهة مستخدم تطبيقك، ما يمنح نظام Android الأساسي آلية مصمّمة خصيصًا للتعامل معها عند تغيُّرها.
هذه الآلية هي إعادة إنشاء Activity.
إعادة إنشاء `Activity`
يعيد النظام إنشاء Activity عند حدوث تغيير في الإعدادات. ولإجراء ذلك، يستدعي النظام onDestroy ويدمّر مثيل Activity
الحالي. بعد ذلك، ينشئ النظام مثيلاً جديدًا باستخدام onCreate، ويتم تهيئة مثيل
Activity الجديد هذا بالإعدادات الجديدة والمعدَّلة. يعني ذلك أيضًا أنّ النظام يعيد إنشاء واجهة المستخدم بالإعدادات الجديدة.
يساعد سلوك إعادة الإنشاء تطبيقك على التكيّف مع الإعدادات الجديدة من خلال إعادة تحميل تطبيقك تلقائيًا بموارد بديلة تتطابق مع إعدادات الجهاز الجديدة.
مثال على إعادة الإنشاء
لنفترض أنّ هناك TextView يعرض عنوانًا ثابتًا باستخدام
android:text="@string/title"، كما هو محدّد في ملف XML للتنسيق. عند إنشاء العرض، يتم ضبط النص مرة واحدة فقط، استنادًا إلى اللغة الحالية. إذا تغيّرت اللغة، يعيد النظام إنشاء النشاط. وبالتالي، يعيد النظام أيضًا إنشاء العرض ويهيئه بالقيمة الصحيحة استنادًا إلى اللغة الجديدة.
تؤدي عملية إعادة الإنشاء أيضًا إلى محو أي حالة يتم الاحتفاظ بها كحقول في Activity أو في أيّ من العناصر Fragment أو View أو الكائنات الأخرى التي يحتوي عليها. يرجع ذلك إلى أنّ عملية إعادة إنشاء Activity تنشئ مثيلاً جديدًا تمامًا من Activity وواجهة المستخدم. علاوةً على ذلك، لم يعُد Activity القديم مرئيًا أو صالحًا، لذا فإنّ أي مراجع متبقية إليه أو إلى الكائنات التي يحتوي عليها تكون قديمة. ويمكن أن تؤدي إلى حدوث أخطاء وتسربات في الذاكرة وحالات تعطل.
توقعات المستخدمين
يتوقع مستخدم التطبيق الاحتفاظ بالحالة. إذا كان المستخدم يملأ نموذجًا وفتح تطبيقًا آخر في وضع النوافذ المتعددة للرجوع إلى معلومات، فستكون تجربة المستخدم سيئة إذا عاد إلى نموذج تم محوه أو إلى مكان آخر في التطبيق بالكامل. بصفتك مطوّرًا، عليك توفير تجربة مستخدم متّسقة من خلال تغييرات الإعدادات وإعادة إنشاء النشاط.
للتحقّق مما إذا تم الاحتفاظ بالحالة في تطبيقك، يمكنك تنفيذ إجراءات تؤدي إلى تغييرات في الإعدادات أثناء تشغيل التطبيق في المقدّمة وأثناء تشغيله في الخلفية. وتتضمن هذه الإجراءات ما يلي:
- تدوير الجهاز
- تفعيل وضع النوافذ المتعددة
- تغيير حجم التطبيق أثناء تشغيله في وضع النوافذ المتعددة أو نافذة ذات شكل حر
- طيّ جهاز قابل للطي مزوّد بشاشات متعددة
- تغيير مظهر النظام، مثل الوضع الداكن مقابل الوضع الفاتح
- تغيير حجم الخط
- تغيير لغة النظام أو التطبيق
- ربط لوحة مفاتيح خارجية أو قطع الاتصال بها
- ربط جهاز إرساء أو قطع الاتصال به
هناك ثلاثة طرق أساسية يمكنك اتّباعها للاحتفاظ بالحالة ذات الصلة من خلال إعادة إنشاء Activity. يعتمد اختيار الطريقة على نوع الحالة التي تريد الاحتفاظ بها:
- الاحتفاظ بالبيانات محليًا للتعامل مع إيقاف العملية نهائيًا للبيانات المعقّدة أو الكبيرة.
تشمل مساحة التخزين المحلية الثابتة قواعد البيانات أو
DataStore. - الكائنات المحتفظ بها، مثل
ViewModel، للتعامل مع الحالة المرتبطة بواجهة المستخدم في الذاكرة أثناء استخدام المستخدم للتطبيق بنشاط. - حالة المثيل المحفوظة للتعامل مع إيقاف العملية نهائيًا الذي بدأه النظام والاحتفاظ بـ الحالة المؤقتة التي تعتمد على بيانات أدخلها المستخدم أو التنقّل.
للاطّلاع على واجهات برمجة التطبيقات لكلّ من هذه الحالات بالتفصيل، ومتى يكون استخدام كلّ منها مناسبًا، يمكنك قراءة مقالة حفظ حالات واجهة المستخدم.
الردّ على تغييرات الإعدادات في نظام العرض
في نظام View، عندما يحدث تغيير في الإعدادات أوقفتَ
إعادة إنشاء Activity له، يتلقّى النشاط طلبًا إلى
Activity.onConfigurationChanged. تتلقّى أيّ طرق عرض مرفقة أيضًا طلبًا إلى View.onConfigurationChanged. بالنسبة إلى تغييرات الإعدادات التي لم تُضِفها إلى android:configChanges، يعيد النظام إنشاء النشاط كالمعتاد.
يتلقّى طريقة رد الاتصال onConfigurationChanged كائن
Configuration يحدّد إعدادات الجهاز الجديدة. يمكنك قراءة الحقول في كائن Configuration لتحديد إعداداتك الجديدة. ولإجراء التغييرات اللاحقة، عدِّل الموارد التي تستخدمها في واجهتك. عندما يستدعي النظام هذه الطريقة، يتم تعديل كائن Resources الخاص بنشاطك لعرض الموارد استنادًا إلى الإعدادات الجديدة. يسمح لك ذلك بإعادة ضبط عناصر واجهة المستخدم بدون أن يعيد النظام تشغيل نشاطك.
على سبيل المثال، يتحقّق تنفيذ onConfigurationChanged التالي مما إذا كانت لوحة المفاتيح متاحة:
Kotlin
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
// Checks whether a keyboard is available
if (newConfig.keyboardHidden === Configuration.KEYBOARDHIDDEN_YES) {
Toast.makeText(this, "Keyboard available", Toast.LENGTH_SHORT).show()
} else if (newConfig.keyboardHidden === Configuration.KEYBOARDHIDDEN_NO) {
Toast.makeText(this, "No keyboard", Toast.LENGTH_SHORT).show()
}
}
Java
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Checks whether a keyboard is available
if (newConfig.keyboardHidden == Configuration.KEYBOARDHIDDEN_YES) {
Toast.makeText(this, "Keyboard available", Toast.LENGTH_SHORT).show();
} else if (newConfig.keyboardHidden == Configuration.KEYBOARDHIDDEN_NO){
Toast.makeText(this, "No keyboard", Toast.LENGTH_SHORT).show();
}
}
إذا لم تكن بحاجة إلى تعديل تطبيقك استنادًا إلى تغييرات الإعدادات هذه، يمكنك بدلاً من ذلك عدم تنفيذ onConfigurationChanged. في هذه الحالة، ستظل جميع الموارد المستخدَمة قبل تغيير الإعدادات مستخدَمة، وقد تجنّبتَ فقط إعادة تشغيل نشاطك. على سبيل المثال، قد لا يرغب تطبيق بث تلفزيوني في الردّ عند ربط لوحة مفاتيح بلوتوث أو قطع الاتصال بها.
الاحتفاظ بالحالة
عند استخدام هذه الطريقة، يجب أن تظل تحتفظ بالحالة أثناء دورة حياة النشاط العادية. يرجع ذلك إلى ما يلي:
- التغييرات التي لا يمكن تجنُّبها: يمكن أن تؤدي تغييرات الإعدادات التي لا يمكنك منعها إلى إعادة تشغيل تطبيقك.
- إيقاف العملية نهائيًا: يجب أن يكون تطبيقك قادرًا على التعامل مع إيقاف العملية نهائيًا الذي بدأه النظام. إذا غادر المستخدم تطبيقك وانتقل التطبيق إلى الخلفية، قد يدمر النظام التطبيق.
تغييرات الإعدادات: المفاهيم الأساسية وأفضل الممارسات
في ما يلي المفاهيم الأساسية التي عليك معرفتها عند العمل على تغييرات الإعدادات:
- الإعدادات: تحدّد إعدادات الجهاز كيفية عرض واجهة المستخدم للمستخدم، مثل حجم عرض التطبيق أو اللغة أو مظهر النظام.
- تغييرات الإعدادات: تتغيّر الإعدادات من خلال تفاعل المستخدم. على سبيل المثال، قد يغيّر المستخدم إعدادات الجهاز أو طريقة تفاعله فعليًا مع الجهاز. لا توجد طريقة لمنع تغييرات الإعدادات.
- إعادة إنشاء
Activity: تؤدي تغييرات الإعدادات إلى إعادة إنشاءActivityتلقائيًا. هذه آلية مضمّنة لإعادة تهيئة حالة التطبيق للإعدادات الجديدة. - تدمير
Activity: تؤدي عملية إعادة إنشاءActivityإلى تدمير النظام لمثيلActivityالقديم وإنشاء مثيل جديد بدلاً منه. أصبح المثيل القديم الآن قديمًا. تؤدي أي مراجع متبقية إليه إلى حدوث تسربات في الذاكرة أو أخطاء أو حالات تعطل. - الحالة: لا تكون الحالة في مثيل
Activityالقديم موجودة في مثيلActivityالجديد، لأنّهما مثيلا كائن مختلفان. يمكنك الاحتفاظ بحالة التطبيق والمستخدم كما هو موضّح في حفظ حالات واجهة المستخدم. - إيقاف الميزة: إنّ إيقاف إعادة إنشاء النشاط لنوع من تغييرات الإعدادات هو تحسين محتمل. يتطلب ذلك أن يحدّث تطبيقك بشكلٍ صحيح ردًا على الإعدادات الجديدة.
لتقديم تجربة مستخدم جيدة، ننصحك باتّباع أفضل الممارسات التالية:
- الاستعداد لتغييرات الإعدادات المتكرّرة: لا تفترض أنّ تغييرات الإعدادات نادرة أو لا تحدث أبدًا، بغض النظر عن مستوى واجهة برمجة التطبيقات أو عامل الشكل أو مجموعة أدوات واجهة المستخدم. عندما يتسبب المستخدم في تغيير الإعدادات، يتوقع أن يتم تعديل التطبيقات وأن تظل تعمل بشكلٍ صحيح مع الإعدادات الجديدة.
- الاحتفاظ بالحالة: لا تفقد حالة المستخدم عند حدوث إعادة إنشاء
Activity. يمكنك الاحتفاظ بالحالة كما هو موضّح في مقالة حفظ حالات واجهة المستخدم. - تجنُّب إيقاف الميزة كحلّ سريع: لا توقِف إعادة إنشاء
Activityكاختصار لتجنُّب فقدان الحالة. يتطلب إيقاف إعادة إنشاء النشاط منك الوفاء بوعد التعامل مع التغيير، وسيظل بإمكانك فقدان الحالة بسبب إعادة إنشاءActivityمن تغييرات الإعدادات الأخرى أو إيقاف العملية نهائيًا أو إغلاق التطبيق. من المستحيل إيقاف إعادة إنشاءActivityبالكامل. يمكنك الاحتفاظ بالحالة كما هو موضّح في مقالة حفظ حالات واجهة المستخدم. - عدم تجنُّب تغييرات الإعدادات: لا تفرض قيودًا على الاتجاه،
نسبة العرض إلى الارتفاع أو إمكانية تغيير الحجم لتجنُّب تغييرات الإعدادات و
Activityإعادة الإنشاء. يؤثر ذلك سلبًا في المستخدمين الذين يريدون استخدام تطبيقك بالطريقة المفضّلة لديهم.
التعامل مع تغييرات الإعدادات المستندة إلى الحجم
يمكن أن تحدث تغييرات الإعدادات المستندة إلى الحجم في أي وقت، ومن المرجّح أن تحدث عندما يتم تشغيل تطبيقك على جهاز ذي شاشة كبيرة حيث يمكن للمستخدمين تفعيل وضع النوافذ المتعددة. ويتوقعون أن يعمل تطبيقك بشكلٍ جيد في هذه البيئة.
هناك نوعان عامّان من تغييرات الحجم: كبيرة وغير كبيرة. تغيير الحجم الكبير هو تغيير يتم فيه تطبيق مجموعة مختلفة من الموارد البديلة على الإعدادات الجديدة بسبب اختلاف في حجم الشاشة، مثل العرض أو الارتفاع أو أصغر عرض. تشمل هذه الموارد تلك التي يحدّدها التطبيق بنفسه وتلك الواردة من أيّ من مكتباته.
تقييد إعادة إنشاء النشاط بسبب تغييرات الإعدادات المستندة إلى الحجم
عند إيقاف إعادة إنشاء Activity بسبب تغييرات الإعدادات المستندة إلى الحجم، لا يعيد النظام إنشاء Activity. بدلاً من ذلك، يتلقّى طلبًا إلى
Activity.onConfigurationChanged. تتلقّى أيّ طرق عرض مرفقة طلبًا إلى
View.onConfigurationChanged.
يتم إيقاف إعادة إنشاء Activity بسبب تغييرات الإعدادات المستندة إلى الحجم عندما
يكون لديك
android:configChanges="screenSize|smallestScreenSize|orientation|screenLayout"
في ملف البيان.
السماح بإعادة إنشاء النشاط بسبب تغييرات الإعدادات المستندة إلى الحجم
في Android 7.0 (المستوى 24 لواجهة برمجة التطبيقات) والإصدارات الأحدث، لا تحدث إعادة إنشاء Activity إلا بسبب تغييرات الإعدادات المستندة إلى الحجم إذا كان تغيير الحجم كبيرًا. عندما
لا يعيد النظام إنشاء Activity بسبب عدم كفاية الحجم، قد يستدعي النظام
Activity.onConfigurationChanged و
View.onConfigurationChanged بدلاً من ذلك.
هناك بعض التحذيرات التي يجب مراعاتها بشأن طرق معاودة الاتصال Activity وView عندما لا يتم إعادة إنشاء Activity:
- في Android 11 (المستوى 30 لواجهة برمجة التطبيقات) إلى Android 13 (المستوى 33 لواجهة برمجة التطبيقات)، لا يتم استدعاء
Activity.onConfigurationChanged. - هناك مشكلة معروفة قد لا يتم فيها استدعاء
View.onConfigurationChangedفي بعض الحالات على Android 12L (المستوى 32 لواجهة برمجة التطبيقات) والإصدارات المبكرة من Android 13 (المستوى 33 لواجهة برمجة التطبيقات). لمزيد من المعلومات، يمكنك الاطّلاع على هذه المشكلة العلنية. تمت معالجة هذه المشكلة منذ ذلك الحين في إصدارات Android 13 اللاحقة وAndroid 14.
بالنسبة إلى الرمز البرمجي الذي يعتمد على الاستماع إلى تغييرات الإعدادات المستندة إلى الحجم
، ننصحك باستخدام أداة View مع
View.onConfigurationChanged تم إلغاؤها بدلاً من الاعتماد على إعادة إنشاء Activity أو
Activity.onConfigurationChanged.