التعامل مع تغييرات الإعدادات

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

  • حجم عرض التطبيق
  • اتجاه الشاشة
  • حجم الخط وعرضه
  • اللغة
  • الوضع الداكن مقابل الوضع الفاتح
  • توفُّر لوحة المفاتيح

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

تتطلب هذه المَعلمات عادةً تغييرات كبيرة بما يكفي في واجهة مستخدم تطبيقك، ما يفسّر سبب توفُّر آلية مخصّصة لها في نظام Android الأساسي عند تغييرها. هذه الآلية هي إعادة إنشاء Activity.

إعادة إنشاء `Activity`

يعيد النظام إنشاء Activity عند حدوث تغيير في الإعدادات. ولإجراء ذل ك، يستدعي النظام onDestroy ويزيل مثيل Activity الحالي. ثم ينشئ مثيلاً جديدًا باستخدام onCreate، ويتم تهيئة مثيل Activity الجديد هذا بالإعدادات الجديدة والمعدَّلة. ويعني ذلك أيضًا أنّ النظام يعيد إنشاء واجهة المستخدم باستخدام الإعدادات الجديدة.

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

يساعد سلوك إعادة الإنشاء تطبيقك على التكيّف مع الإعدادات الجديدة من خلال إعادة تحميل تطبيقك تلقائيًا باستخدام موارد بديلة تتطابق مع إعدادات الجهاز الجديدة.

مثال على إعادة الإنشاء

لنفترض أنّ هناك دالة مركّبة تعرض عنوانًا ثابتًا باستخدام مصدر السلاسل النصية:

// In the res/values/strings.xml file
// <string name="compose">Jetpack Compose</string>

// In your Compose code
Text(
    text = stringResource(R.string.compose)
)

عند إنشاء Activity، يقرأ العنصر المركّب Text الإعدادات الحالية (مثل اللغة) ويحلّ مورد السلسلة المناسب.

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

تؤدي عملية إعادة الإنشاء أيضًا إلى محو أي حالة يتم الاحتفاظ بها كحقول في Activity.

للحفاظ على حالة واجهة المستخدم عند تغيير الإعدادات، استخدِم أنماط إدارة الحالة المقترَحة. استخدِم ViewModel للبيانات ومنطق النشاط التجاري، واستخدِم rememberSaveable للحالة على مستوى واجهة المستخدم. باستخدام هاتَين الآليتَين، تظل حالتك محفوظة أثناء إعادة إنشاء Activity، بينما يتم تعديل واجهة المستخدم لتعكس الإعدادات الجديدة.

لمزيد من المعلومات عن حفظ الحالة في Compose، يُرجى الاطّلاع على مقالة حفظ حالة واجهة المستخدم في Compose.

توقعات المستخدمين

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

للتحقّق مما إذا كانت الحالة محفوظة في تطبيقك، يمكنك تنفيذ إجراءات تؤدي إلى تغييرات في الإعدادات أثناء وجود التطبيق في المقدّمة وأثناء وجوده في الخلفية. وتشمل هذه الإجراءات ما يلي:

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

هناك عدة طرق يمكنك اتّباعها للحفاظ على الحالة ذات الصلة أثناء إعادة إنشاء Activity. يعتمد الخيار الذي يجب استخدامه على نوع الحالة التي تريد الحفاظ عليها:

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

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

تقييد إعادة إنشاء النشاط

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

تؤدي تغييرات الإعدادات تلقائيًا إلى إجبار النظام على محو `Activity` وإعادة إنشائه، بما في ذلك واجهة المستخدم وأي عناصر مشتقة من `Activity`. إذا أعلنت أنّ `Activity` يتعامل مع تغيير الإعدادات بنفسه، يمنع النظام ذلك. بدلاً من ذلك، يتم تعديل عنصر Configuration فقط، ويعيد Compose إنشاء واجهة المستخدم باستخدام القيم الجديدة.

يوفّر التعامل مع تغييرات الإعدادات مباشرةً في Compose عدة مزايا:

  • تحسين الأداء: إنّ إعادة إنشاء واجهة المستخدم أقل تكلفة من دورة إعادة إنشاء `Activity` كاملة، خاصةً بالنسبة إلى التغييرات الطفيفة.
  • الرسوم المتحركة السلسة: يتيح لك تجنُّب إعادة تشغيل `Activity` عرض رسوم متحركة مستمرة عند تغيير الإعدادات، مثل عمليات الانتقال السلسة في التنسيق أثناء تدوير الجهاز.
  • الحفاظ على الحالة: يقلّل الاحتفاظ بمثيل `Activity` من خطر فقدان حالة واجهة المستخدم المؤقتة أثناء حدث مثل تدوير الشاشة. يُرجى العِلم أنّه لا يزال عليك التعامل مع الحفاظ على الحالة عند إيقاف العملية من قِبل النظام.

لإيقاف إعادة إنشاء النشاط عند حدوث تغييرات معيّنة في الإعدادات، أضِف نوع الإعداد إلى android:configChanges في <activity> في ملف AndroidManifest.xml. تظهر القيم المحتمَلة في مستندات السمة android:configChanges.

يوقف رمز البيان التالي إعادة إنشاء Activity لـ MyActivity عند تغيير اتجاه الشاشة وتوفُّر لوحة المفاتيح:

<activity
    android:name=".MyActivity"
    android:configChanges="orientation|screenSize|screenLayout|keyboardHidden"
    android:label="@string/app_name">

Android 17

بدءًا من Android 17 (المستوى 37 من واجهة برمجة التطبيقات)، لم يعُد النظام يعيد تشغيل الأنشطة تلقائيًا عند حدوث عدة تغييرات في الإعدادات لا تتطلب عادةً إعادة إنشاء واجهة المستخدم بالكامل. بدلاً من ذلك، تظل الأنشطة نشطة وتتلقّى التعديلات من خلال الـ onConfigurationChanged() callback. تشمل تغييرات الإعدادات المحدّدة ما يلي:

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

<activity
    android:name=".MyActivity"
    android:recreateOnConfigChanges="keyboard|keyboardHidden|navigation|colorMode|touchscreen|...">
    ...
</activity>

الردّ على تغييرات الإعدادات

يتيح Jetpack Compose لتطبيقك الردّ بسهولة أكبر على تغييرات الإعدادات. ومع ذلك، إذا أوقفت إعادة إنشاء Activity لجميع تغييرات الإعدادات التي يمكن إيقافها، سيظل على تطبيقك التعامل مع تغييرات الإعدادات بشكل صحيح.

يتوفّر عنصر Configuration في تسلسل Compose UI الهرمي باستخدام التركيبة المحلية LocalConfiguration. عندما يتغيّر، تتم إعادة إنشاء الدوال المركّبة التي تقرأ من LocalConfiguration.current. لمعرفة طريقة عمل التركيبات المحلية، يُرجى الاطّلاع على مقالة البيانات ذات النطاق المحلي باستخدام CompositionLocal.

مثال

في المثال التالي، تعرض دالة مركّبة تاريخًا بتنسيق معيّن. يردّ العنصر المركّب على تغييرات إعدادات اللغة في النظام من خلال استدعاء ConfigurationCompat.getLocales باستخدام LocalConfiguration.current.

@Composable
fun DateText(year: Int, dayOfYear: Int) {
    val dateTimeFormatter = DateTimeFormatter.ofPattern(
        "MMM dd",
        ConfigurationCompat.getLocales(LocalConfiguration.current)[0]
    )
    Text(
        dateTimeFormatter.format(LocalDate.ofYearDay(year, dayOfYear))
    )
}

لتجنُّب إعادة إنشاء Activity عند تغيير اللغة، يجب أن يرفض Activity الذي يستضيف رمز Compose تغييرات إعدادات اللغة. لإجراء ذلك، اضبط android:configChanges على locale|layoutDirection.

تغييرات الإعدادات: المفاهيم الأساسية وأفضل الممارسات

في ما يلي المفاهيم الأساسية التي عليك معرفتها عند العمل على تغييرات الإعدادات:

  • الإعدادات: تحدّد إعدادات الجهاز طريقة عرض واجهة المستخدم للمستخدم، مثل حجم عرض التطبيق أو اللغة أو مظهر النظام. في Compose، يمكنك الوصول إلى قيم الإعدادات باستخدام LocalConfiguration.
  • تغييرات الإعدادات: تتغيّر الإعدادات من خلال تفاعل المستخدم. على سبيل المثال، قد يغيّر المستخدم إعدادات الجهاز أو طريقة تفاعله فعليًا مع الجهاز. لا يمكن منع تغييرات الإعدادات.
  • إعادة إنشاء Activity: تؤدي تغييرات الإعدادات تلقائيًا إلى إعادة إنشاء Activity. هذه آلية مضمّنة لإعادة تهيئة حالة التطبيق للإعدادات الجديدة.
  • إزالة Activity: تؤدي إعادة إنشاء Activity إلى إزالة النظام لمثيل Activity القديم وإنشاء مثيل جديد بدلاً منه. أصبح المثيل القديم الآن قديمًا. تجنَّب الاحتفاظ بمراجع للكائنات ذات النطاق المحدّد بدورة الحياة بعد نطاقها المقصود.
  • الحالة: لا تتوفّر الحالة في مثيل Activity القديم في مثيل Activity الجديد، لأنّهما مثيلا كائن مختلفَين. بدلاً من ربط الحالة بـ `Activity`، استخدِم واجهات برمجة التطبيقات المقترَحة للحفاظ على حالة التطبيق والمستخدم كما هو موضّح في حفظ حالات واجهة المستخدم.
  • إيقاف الميزة: يتطلب إيقاف ميزة إعادة إنشاء النشاط لنوع معيّن من تغييرات الإعدادات أن يتم تعديل تطبيقك بشكل صحيح ردًا على الإعدادات الجديدة.

لتوفير تجربة مستخدم جيدة، ننصحك باتّباع أفضل الممارسات التالية:

  • الاستعداد لتغييرات الإعدادات المتكررة: لا تفترض أنّ تغييرات الإعدادات نادرة أو لا تحدث أبدًا، بغض النظر عن مستوى واجهة برمجة التطبيقات أو شكل الجهاز أو مجموعة أدوات واجهة المستخدم. عندما يتسبب المستخدم في تغيير الإعدادات، يتوقع أن يتم تعديل التطبيقات وأن تستمر في العمل بشكل صحيح باستخدام الإعدادات الجديدة.
  • الحفاظ على الحالة: لا تفقد حالة المستخدم عند إعادة إنشاء Activity. احتفِظ بالحالة كما هو موضّح في حفظ حالات واجهة المستخدم باستخدام واجهات برمجة التطبيقات مثل ViewModel وrememberSaveable.
  • تجنُّب إيقاف الميزة كحلّ سريع: لا توقف ميزة إعادة إنشاء Activity كطريقة مختصرة لتجنُّب فقدان الحالة. يتطلب إيقاف ميزة إعادة إنشاء النشاط الوفاء بوعد التعامل مع التغيير، ولا يزال بإمكانك فقدان الحالة بسبب إعادة إنشاء Activity من تغييرات الإعدادات الأخرى أو إيقاف العملية أو إغلاق التطبيق. من المستحيل إيقاف إعادة إنشاء Activity بالكامل. احتفِظ بالحالة كما هو موضّح في مقالة حفظ حالات واجهة المستخدم.
  • عدم تجنُّب تغييرات الإعدادات: لا تفرض قيودًا على الاتجاه، نسبة العرض إلى الارتفاع أو إمكانية تغيير الحجم لتجنُّب تغييرات الإعدادات و Activity إعادة الإنشاء. يؤثر ذلك سلبًا في المستخدمين الذين يريدون استخدام تطبيقك بالطريقة المفضّلة لديهم.

التعامل مع تغييرات الإعدادات المستندة إلى الحجم

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

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

تقييد إعادة إنشاء النشاط عند حدوث تغييرات في الإعدادات المستندة إلى الحجم

عند إيقاف ميزة إعادة إنشاء Activity عند حدوث تغييرات في الإعدادات المستندة إلى الحجم، لا يعيد النظام إنشاء Activity. بدلاً من ذلك، يتلقّى النظام استدعاءً لـ Activity.onConfigurationChanged. تتم إعادة إنشاء أي عناصر مركّبة تقرأ LocalConfiguration.current تلقائيًا لتعكس الحجم الجديد.

يتم إيقاف إعادة إنشاء Activity عند حدوث تغييرات في الإعدادات المستندة إلى الحجم عندما يكون لديك android:configChanges="screenSize|smallestScreenSize|orientation|screenLayout" في ملف البيان.

مراجع إضافية

لمزيد من المعلومات عن التعامل مع تغييرات الإعدادات، يُرجى الاطّلاع على المراجع الإضافية التالية:

الوثائق

عرض المحتوى