مدیریت تغییرات پیکربندی

برخی پیکربندی‌های دستگاه ممکن است درحین اجرای برنامه تغییر کند. این موارد شامل، اما نه محدود به، موارد زیر است:

  • اندازه نمایش برنامه
  • تراکم صفحه‌نمایش (مقیاس‌بندی نمایش)
  • جهت صفحه‌نمایش
  • اندازه و سیاهی قلم
  • منطقه زبانی
  • زمینه تیره درمقابل زمینه روشن
  • دردسترس بودن صفحه‌کلید

بیشتر این تغییرات پیکربندی به‌دلیل برخی تعاملات کاربر رخ می‌دهد. برای مثال، چرخاندن یا تا کردن دستگاه، مقدار فضای صفحه‌نمایش دردسترس برای برنامه شما را تغییر می‌دهد. اتصال به نمایشگرهای خارجی یا جابه‌جایی برنامه بین نمایشگرهایی با تراکم پیکسلی متفاوت، تراکم صفحه‌نمایش و اندازه نمایشگر را تغییر می‌دهد. به‌همین ترتیب، تغییر تنظیمات دستگاه مانند مقیاس‌بندی نمایشگر، اندازه قلم، زبان، یا طرح زمینه ترجیحی، مقادیر مربوطه را در شیء Configuration تغییر می‌دهد.

این پارامترها معمولاً به تغییرات به‌اندازه کافی بزرگ در واسط کاربر برنامه شما نیاز دارند که پلاتفرم Android سازوکاری هدفمند برای زمان تغییر آن‌ها دارد. این سازوکار Activity بازآفرینی است.

تفریح و سرگرمی

وقتی تغییر پیکربندی رخ می‌دهد، سیستم Activity را بازسازی می‌کند. برای انجام این کار، سیستم onDestroy را فراخوانی می‌کند و نمونه Activity موجود را ازبین می‌برد. سپس نمونه جدیدی بااستفاده از onCreate ایجاد می‌کند و این نمونه جدید Activity با پیکربندی جدید و به‌روزشده مقداردهی اولیه می‌شود. این همچنین به این معنی است که سیستم میانای کاربری را با پیکربندی جدید بازسازی می‌کند.

معمولاً Activity به‌عنوان میزبان برای composableها عمل می‌کند. وقتی Activity دوباره ایجاد می‌شود، Compose نیز بااستفاده از مقادیر پیکربندی جدید، واسط کاربر را دوباره ایجاد می‌کند.

رفتار بازآفرینی به برنامه شما کمک می‌کند تا با بارگیری مجدد خودکار برنامه با منابع جایگزین که با پیکربندی دستگاه جدید مطابقت دارند، با پیکربندی‌های جدید سازگار شود.

نمونه تفریح

یک composable را درنظر بگیرید که عنوان ثابتی را بااستفاده از منبع رشته‌ای نمایش می‌دهد:

// 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، واسط کاربر شما به هر دو روش بازترکیب می‌شود، اما توصیه می‌شود تغییر پیکربندی را مستقیماً مدیریت کنید.

به‌طور پیش‌فرض، تغییر پیکربندی سیستم را مجبور می‌کند «فعالیت» را ازبین ببرد و دوباره ایجاد کند، ازجمله واسط کاربر و هر شیء مشتق‌شده از «فعالیت». اگر اعلام کنید که «فعالیت» شما خودش تغییر پیکربندی را مدیریت می‌کند، سیستم از این کار جلوگیری می‌کند. درعوض، فقط شیء 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

از Android 17 (سطح API‏ ۳۷) به بعد، سیستم دیگر به‌طور پیش‌فرض فعالیت‌ها را برای چندین تغییر پیکربندی که معمولاً نیازی به بازسازی کامل رابط کاربری ندارند، بازراه‌اندازی نمی‌کند. درعوض، فعالیت‌ها فعال می‌مانند و به‌روزرسانی‌ها را ازطریق 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 را ببینید.

مثال

در مثال زیر، یک composable تاریخ را با قالب خاصی نمایش می‌دهد. The composable reacts to system locale configuration changes by calling ConfigurationCompat.getLocales with 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 وجود ندارد، زیرا آن‌ها دو نمونه شیء متفاوت هستند. به‌جای گره زدن حالت به «فعالیت»، از میاناهای برنامه‌سازی کاربردی توصیه‌شده برای حفظ حالت برنامه و کاربر استفاده کنید، همان‌طور که در ذخیره کردن حالت‌های میانای کاربر شرح داده شده است.
  • انصراف: انصراف از بازسازی فعالیت برای نوعی تغییر پیکربندی مستلزم این است که برنامه‌تان به‌درستی در واکنش به پیکربندی جدید به‌روز شود.

برای ارائه تجربه کاربری خوب، روال‌های مطلوب زیر را رعایت کنید:

  • برای تغییرات مکرر پیکربندی آماده باشید: فرض نکنید که تغییرات پیکربندی نادر هستند یا هرگز اتفاق نمی‌افتند، صرف‌نظر از سطح API، فرم فاکتور، یا جعبه ابزار UI. وقتی کاربر باعث تغییر پیکربندی می‌شود، انتظار دارد برنامه‌ها به‌روز شوند و با پیکربندی جدید به‌درستی کار کنند.
  • حفظ وضعیت: وضعیت کاربر را هنگام بازسازی Activity ازدست ندهید. وضعیت را همان‌طور که در ذخیره کردن وضعیت‌های میانای کاربر شرح داده شده است بااستفاده از میاناهای برنامه‌سازی کاربردی مثل ViewModel و rememberSaveable حفظ کنید.
  • از انصراف دادن به‌عنوان راه‌حل سریع اجتناب کنید: از بازآفرینی Activity به‌عنوان میان‌بری برای جلوگیری از دست دادن وضعیت انصراف ندهید. انصراف از بازسازی فعالیت مستلزم این است که شما به وعده خود برای مدیریت تغییر عمل کنید، و همچنان ممکن است وضعیت را به‌دلیل بازسازی Activity ناشی از سایر تغییرات پیکربندی، مرگ پردازش، یا بستن برنامه ازدست بدهید. غیرفعال کردن کامل بازسازی Activity غیرممکن است. وضعیت را همان‌طور که در ذخیره کردن وضعیت‌های میانای کاربر شرح داده شده است حفظ کنید.
  • از تغییرات پیکربندی اجتناب نکنید: برای اجتناب از تغییرات پیکربندی و Activity بازآفرینی، محدودیت‌هایی برای جهت، نسبت ابعادی، یا قابلیت تغییر اندازه اعمال نکنید. این امر بر کاربرانی که می‌خواهند از برنامه شما به روش دلخواهشان استفاده کنند تأثیر منفی می‌گذارد.

مدیریت تغییرات پیکربندی مبتنی بر اندازه

تغییرات پیکربندی مبتنی بر اندازه ممکن است در هر زمانی اتفاق بیفتد و احتمال وقوع آن زمانی بیشتر است که برنامه شما در دستگاهی با صفحه‌نمایش بزرگ اجرا شود که کاربران می‌توانند وارد حالت چندپنجره‌ای شوند. آن‌ها انتظار دارند برنامه‌تان در آن محیط به‌خوبی کار کند.

دو نوع کلی تغییر اندازه وجود دارد: قابل‌توجه و غیرقابل‌توجه. تغییر اندازه قابل‌توجه تغییری است که در آن مجموعه متفاوتی از منابع جایگزین به‌دلیل تفاوت در اندازه صفحه‌نمایش (مانند عرض، ارتفاع، یا کوچک‌ترین عرض) برای پیکربندی جدید اعمال می‌شود. این منابع شامل منابعی است که برنامه خودش تعریف می‌کند و منابعی که از کتابخانه‌هایش می‌آید.

محدود کردن بازآفرینی فعالیت برای تغییرات پیکربندی مبتنی بر اندازه

وقتی بازسازی Activity را برای تغییرات پیکربندی مبتنی بر اندازه غیرفعال می‌کنید، سیستم Activity را بازسازی نمی‌کند. درعوض، تماسی با Activity.onConfigurationChanged دریافت می‌کند. هر ترکیب‌پذیری که LocalConfiguration.current را می‌خواند، به‌طور خودکار بازترکیب می‌شود تا اندازه جدید را منعکس کند.

وقتی android:configChanges="screenSize|smallestScreenSize|orientation|screenLayout" را در فایل مانیفست خود داشته باشید، بازآفرینی Activity برای تغییرات پیکربندی مبتنی بر اندازه غیرفعال می‌شود.

منابع بیشتر

برای اطلاعات بیشتر درباره رسیدگی به تغییرات پیکربندی، منابع تکمیلی زیر را ببینید:

اسناد

محتوا را مشاهده می‌کند