برخی از پیکربندیهای دستگاه میتوانند در حین اجرای برنامه تغییر کنند. این موارد شامل موارد زیر است، اما محدود به آنها نیست:
- اندازه نمایش برنامه
- جهت گیری صفحه نمایش
- اندازه و وزن فونت
- محلی
- حالت تاریک در مقابل حالت روشن
- در دسترس بودن صفحه کلید
بیشتر این تغییرات پیکربندی به دلیل برخی تعاملات کاربر رخ میدهد. برای مثال، چرخاندن یا تا کردن دستگاه، میزان فضای صفحه نمایش موجود برای برنامه شما را تغییر میدهد. به همین ترتیب، تغییر تنظیمات دستگاه مانند اندازه فونت، زبان یا تم مورد نظر، مقادیر مربوط به آنها را در شیء Configuration تغییر میدهد.
این پارامترها معمولاً به تغییرات بزرگی در رابط کاربری برنامه شما نیاز دارند، به طوری که پلتفرم اندروید برای زمان تغییر آنها، مکانیزمی هدفمند دارد. این مکانیزم Activity recreation نام دارد.
فعالیت تفریحی
سیستم هنگامی که تغییری در پیکربندی رخ میدهد، یک 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 پیکربندی فعلی (مانند زبان) را میخواند و منبع رشتهای مناسب را حل میکند.
اگر زبان تغییر کند، سیستم activity را دوباره ایجاد میکند. وقتی این اتفاق میافتد، Compose رابط کاربری را دوباره ایجاد میکند. از آنجایی که stringResource از پیکربندی فعلی میخواند، عنوان به طور خودکار به مقدار محلی صحیح بهروزرسانی میشود.
این بازسازی همچنین هر حالتی را که به عنوان فیلد در Activity نگه داشته شده است، پاک میکند.
برای حفظ وضعیت رابط کاربری (UI) خود در طول تغییرات پیکربندی، از الگوهای مدیریت وضعیت توصیهشده استفاده کنید. برای دادهها و منطق کسبوکار از ViewModel و برای وضعیت سطح رابط کاربری rememberSaveable استفاده کنید. با این مکانیسمها، وضعیت شما در طول بازآفرینی Activity حفظ میشود در حالی که رابط کاربری برای انعکاس پیکربندی جدید بهروزرسانی میشود.
برای اطلاعات بیشتر در مورد ذخیره وضعیت در Compose، به «ذخیره وضعیت رابط کاربری در Compose» مراجعه کنید.
انتظارات کاربران
کاربر یک برنامه انتظار دارد که وضعیت (state) حفظ شود. اگر کاربری در حال پر کردن فرمی باشد و برنامه دیگری را در حالت چند پنجرهای برای مراجعه به اطلاعات باز کند، اگر به فرم پاک شده یا به جای دیگری در برنامه بازگردد، تجربه کاربری بدی خواهد داشت. به عنوان یک توسعهدهنده، شما باید از طریق تغییرات پیکربندی و بازآفرینی فعالیتها، یک تجربه کاربری پایدار ارائه دهید.
برای تأیید اینکه آیا وضعیت (state) در برنامه شما حفظ شده است یا خیر، میتوانید اقداماتی را انجام دهید که باعث تغییرات پیکربندی هم در زمانی که برنامه در پیشزمینه (foreground) و هم در زمانی که در پسزمینه (background) است، میشوند. این اقدامات عبارتند از:
- چرخاندن دستگاه
- ورود به حالت چند پنجرهای
- تغییر اندازه برنامه در حالت چند پنجرهای یا پنجره آزاد
- تا کردن یک دستگاه تاشو با چندین نمایشگر
- تغییر تم سیستم، مانند حالت تاریک در مقابل حالت روشن
- تغییر اندازه فونت
- تغییر زبان سیستم یا برنامه
- اتصال یا قطع اتصال صفحه کلید سخت افزاری
- اتصال یا قطع اتصال داک
چندین رویکرد وجود دارد که میتوانید برای حفظ وضعیت مربوطه از طریق Activity Recreation اتخاذ کنید. استفاده از هر کدام به نوع وضعیتی که میخواهید حفظ کنید بستگی دارد:
- ماندگاری محلی برای مدیریت مرگ فرآیند برای دادههای پیچیده یا بزرگ. ذخیرهسازی محلی پایدار شامل پایگاههای داده یا
DataStoreمیشود. - اشیاء حفظشده مانند نمونههای
ViewModelبرای مدیریت وضعیت مربوط به رابط کاربری در حافظه در حالی که کاربر به طور فعال از برنامه استفاده میکند. -
rememberSaveableبرای حفظ حالت گذرای رابط کاربری در طول تغییرات پیکربندی و مرگ فرآیند آغاز شده توسط سیستم. این برای حالتی مناسب است که به ورودی کاربر، موقعیت اسکرول یا ناوبری بستگی دارد اما بهViewModelتعلق ندارد.
برای مطالعهی جزئیات APIهای مربوط به هر یک از این موارد، و زمان مناسب استفاده از هر یک، به بخش «ذخیره حالتهای رابط کاربری» مراجعه کنید.
محدود کردن فعالیتها و تفریحات
شما میتوانید از اجرای خودکار فعالیتها برای تغییرات پیکربندی خاص جلوگیری کنید. در برنامههای مدرن فقط-نوشتن (Compose-only)، رابط کاربری شما در هر صورت دوباره نوشته میشود، اما توصیه میشود که تغییر پیکربندی را مستقیماً مدیریت کنید.
به طور پیشفرض، یک تغییر پیکربندی، سیستم را مجبور میکند تا Activity، شامل UI و هر شیء مشتق شده از Activity را نابود و دوباره ایجاد کند. اگر اعلام کنید که Activity شما خودش تغییر پیکربندی را مدیریت میکند، سیستم از این کار جلوگیری میکند. در عوض، فقط شیء Configuration بهروزرسانی میشود و Compose رابط کاربری شما را با مقادیر جدید دوباره ترکیب میکند.
مدیریت مستقیم تغییرات پیکربندی در Compose مزایای متعددی دارد:
- بهبود عملکرد: بازسازی رابط کاربری، به خصوص برای تغییرات جزئی، ارزانتر از یک چرخه کامل بازسازی فعالیت است.
- انیمیشنهای روان: جلوگیری از راهاندازی مجدد 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">
واکنش به تغییرات پیکربندی
Jetpack Compose به برنامه شما اجازه میدهد تا راحتتر به تغییرات پیکربندی واکنش نشان دهد. با این حال، اگر Activity recreation را برای همه تغییرات پیکربندی که امکان انجام آن وجود دارد غیرفعال کنید، برنامه شما همچنان باید تغییرات پیکربندی را به درستی مدیریت کند.
شیء Configuration در سلسله مراتب رابط کاربری Compose با ترکیب LocalConfiguration local در دسترس است. هر زمان که تغییر کند، توابع composable که از LocalConfiguration.current میخواند، آن را دوباره ترکیب میکنند. برای اطلاعات بیشتر در مورد نحوه کار ترکیبهای محلی، به دادههای محلی با CompositionLocal مراجعه کنید.
مثال
در مثال زیر، یک composable تاریخ را با فرمت خاصی نمایش میدهد. composable با فراخوانی 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، از API های توصیه شده برای حفظ وضعیت برنامه و کاربر، همانطور که در بخش «ذخیره وضعیتهای رابط کاربری» توضیح داده شده است، استفاده کنید. - انصراف: انصراف از فعالیت تفریحی برای نوعی تغییر پیکربندی مستلزم آن است که برنامه شما به درستی در واکنش به پیکربندی جدید بهروزرسانی شود. برای اکثر برنامههای Compose، این توصیه نمیشود.
برای ارائه یک تجربه کاربری خوب، نکات زیر را رعایت کنید:
- برای تغییرات مکرر پیکربندی آماده باشید: صرف نظر از سطح API، فرم فاکتور یا ابزار رابط کاربری، تصور نکنید که تغییرات پیکربندی نادر هستند یا هرگز اتفاق نمیافتند. وقتی کاربری باعث تغییر پیکربندی میشود، انتظار دارد برنامهها بهروزرسانی شوند و با پیکربندی جدید به درستی کار کنند.
- حفظ وضعیت: وقتی
Activityدوباره اجرا میشود، وضعیت کاربر را از دست ندهید. وضعیت را همانطور که در بخش «ذخیره وضعیتهای رابط کاربری» توضیح داده شده است، با استفاده از APIهایی مانندViewModelوrememberSaveableحفظ کنید. - از انصراف به عنوان یک راه حل سریع خودداری کنید: برای جلوگیری از از دست دادن وضعیت، از
Activityrecreation به عنوان یک میانبر انصراف ندهید. انصراف از activity recreation مستلزم آن است که شما به وعده مدیریت تغییر عمل کنید و همچنان ممکن است به دلیلActivityrecreation از سایر تغییرات پیکربندی، مرگ فرآیند یا بستن برنامه، وضعیت را از دست بدهید. غیرفعال کردن کاملActivityrecreation غیرممکن است. وضعیت را همانطور که در Save UI states توضیح داده شده است، حفظ کنید. - از تغییرات پیکربندی اجتناب نکنید: برای جلوگیری از تغییرات پیکربندی و ایجاد مجدد
Activity، محدودیتی در جهتگیری، نسبت ابعاد یا قابلیت تغییر اندازه ایجاد نکنید. این امر بر کاربرانی که میخواهند از برنامه شما به روش دلخواه خود استفاده کنند، تأثیر منفی میگذارد.
مدیریت تغییرات پیکربندی مبتنی بر اندازه
تغییرات پیکربندی مبتنی بر اندازه میتواند در هر زمانی اتفاق بیفتد و زمانی که برنامه شما روی یک دستگاه با صفحه نمایش بزرگ اجرا میشود که کاربران میتوانند وارد حالت چند پنجرهای شوند، احتمال وقوع آن بیشتر است. آنها انتظار دارند برنامه شما در آن محیط به خوبی کار کند.
دو نوع کلی تغییر اندازه وجود دارد: قابل توجه و غیر قابل توجه. تغییر اندازه قابل توجه ، تغییری است که در آن مجموعه متفاوتی از منابع جایگزین به دلیل تفاوت در اندازه صفحه نمایش، مانند عرض، ارتفاع یا کمترین عرض، برای پیکربندی جدید اعمال میشود. این منابع شامل مواردی است که خود برنامه تعریف میکند و منابعی که از هر یک از کتابخانههای آن گرفته شدهاند.
محدود کردن فعالیتهای تفریحی برای تغییرات پیکربندی مبتنی بر اندازه
وقتی شما Activity Reproduction را برای تغییرات پیکربندی مبتنی بر اندازه غیرفعال میکنید، سیستم Activity را دوباره ایجاد نمیکند. در عوض، فراخوانی به Activity.onConfigurationChanged دریافت میکند. هر composable که LocalConfiguration.current میخواند، به طور خودکار برای انعکاس اندازه جدید، recompose میشود.
وقتی در فایل مانیفست خود android:configChanges="screenSize|smallestScreenSize|orientation|screenLayout" دارید، بازآفرینی Activity برای تغییرات پیکربندی مبتنی بر اندازه غیرفعال است.
منابع اضافی
برای اطلاعات بیشتر در مورد مدیریت تغییرات پیکربندی، به منابع اضافی زیر مراجعه کنید: