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

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

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

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

تتطلب هذه المَعلمات عادةً تغييرات كبيرة بما يكفي في واجهة مستخدم تطبيقك بحيث يكون لنظام Android الأساسي آلية مخصّصة عند تغييرها. هذه الآلية هي 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 فقط، تتم إعادة إنشاء واجهة المستخدم في كلتا الحالتين، ولكن يُنصح بمعالجة تغيير الإعدادات مباشرةً.

By default, a configuration change forces the system to destroy and recreate the Activity, including the UI and any objects derived from the Activity. إذا أعلنت أن نشاطك يتعامل مع تغيير التكوين نفسه، فإن النظام يمنع ذلك. بدلاً من ذلك، يتم تعديل عنصر Configuration فقط، ويعيد Compose إنشاء واجهة المستخدم بالقيم الجديدة.

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

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

لإيقاف إعادة إنشاء النشاط لتغييرات معيّنة في الإعدادات، أضِف نوع الإعدادات إلى 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

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

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

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

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

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

يتوفّر عنصر Configuration في التسلسل الهرمي لواجهة مستخدم Compose مع التركيبة المحلية 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. يمكنك الحفاظ على الحالة كما هو موضّح في حفظ حالات واجهة المستخدم باستخدام واجهات برمجة التطبيقات، مثل ViewModel وrememberSaveable.
  • تجنَّب إيقاف إعادة إنشاء كحل سريع: لا توقف إعادة إنشاء Activity كحل سريع لتجنُّب فقدان الحالة. يتطلّب إيقاف إعادة إنشاء النشاط الوفاء بوعد معالجة التغيير، ولا يزال بإمكانك فقدان الحالة بسبب إعادة إنشاء Activity من تغييرات الضبط الأخرى أو إيقاف العملية نهائيًا أو إغلاق التطبيق. من المستحيل إيقاف إعادة إنشاء Activity تمامًا. احتفِظ بالحالة كما هو موضّح في حفظ حالات واجهة المستخدم.
  • لا تتجنَّب تغييرات الإعدادات: لا تضع قيودًا على الاتجاه أو نسبة العرض إلى الارتفاع أو إمكانية تغيير الحجم لتجنُّب تغييرات الإعدادات وإعادة إنشاء Activity. ويؤثر ذلك سلبًا في المستخدمين الذين يريدون استخدام تطبيقك بالطريقة المفضّلة لديهم.

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

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

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

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

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

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

مراجع إضافية

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

الوثائق

محتوى المشاهدات