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

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

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

تحدث معظم تغييرات الإعدادات هذه بسبب تفاعل المستخدم. على سبيل المثال، يؤدي تدوير الجهاز أو طيّه إلى تغيير مساحة الشاشة المتاحة لتطبيقك. ويؤدي الاتصال بشاشات خارجية أو نقل تطبيق بين شاشات ذات كثافات بكسل مختلفة إلى تغيير كثافة الشاشة وحجم العرض. وبالمثل، يؤدي تغيير إعدادات الجهاز، مثل تغيير حجم العرض أو حجم الخط أو اللغة أو المظهر المفضّل، إلى تغيير القيم المقابلة لها في الـ 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 composition local. عندما يتغيّر، تتم إعادة إنشاء الدوال المركّبة التي تقرأ من LocalConfiguration.current. لمزيد من المعلومات عن طريقة عمل composition locals، يُرجى الاطّلاع على مقالة البيانات ذات النطاق المحلي باستخدام 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" في ملف البيان.

مراجع إضافية

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

الوثائق

عرض المحتوى