حالت در برنامه هر مقداری است که می تواند در طول زمان تغییر کند. این یک تعریف بسیار گسترده است و همه چیز را از یک پایگاه داده اتاق گرفته تا یک متغیر در یک کلاس را در بر می گیرد.
همه برنامه های اندروید وضعیت را به کاربر نمایش می دهند. چند نمونه از حالت در برنامه های اندروید:
- یک نوار اسنک که نشان می دهد چه زمانی اتصال شبکه نمی تواند برقرار شود.
- یک پست وبلاگ و نظرات مرتبط.
- انیمیشنها را روی دکمههایی که وقتی کاربر روی آنها کلیک میکند پخش میشوند.
- برچسب هایی که کاربر می تواند روی یک تصویر بکشد.
Jetpack Compose به شما کمک میکند در مورد مکان و نحوه ذخیره و استفاده از وضعیت در یک برنامه Android صریح باشید. این راهنما بر ارتباط بین state و composable ها، و API هایی که Jetpack Compose برای کار راحت تر با state ارائه می دهد، تمرکز دارد.
حالت و ترکیب
Compose اعلانی است و به این ترتیب تنها راه برای به روز رسانی آن فراخوانی همان composable با آرگومان های جدید است. این آرگومان ها نمایشی از وضعیت UI هستند. هر زمان که وضعیتی به روز می شود، ترکیب مجدد صورت می گیرد. در نتیجه، چیزهایی مانند TextField
به طور خودکار مانند نماهای ضروری مبتنی بر XML به روز نمی شوند. به یک composable باید به صراحت وضعیت جدید گفته شود تا مطابق آن به روز شود.
@Composable private fun HelloContent() { Column(modifier = Modifier.padding(16.dp)) { Text( text = "Hello!", modifier = Modifier.padding(bottom = 8.dp), style = MaterialTheme.typography.bodyMedium ) OutlinedTextField( value = "", onValueChange = { }, label = { Text("Name") } ) } }
اگر این را اجرا کنید و سعی کنید متن را وارد کنید، خواهید دید که هیچ اتفاقی نمی افتد. دلیلش این است که TextField
خودش را به روز نمی کند - زمانی که پارامتر value
آن تغییر می کند، به روز می شود. این به دلیل نحوه کار ترکیب و ترکیب مجدد در Compose است.
برای کسب اطلاعات بیشتر در مورد ترکیب اولیه و ترکیب مجدد، به تفکر در نوشتن مراجعه کنید.
حالت در ترکیبات
توابع Composable می توانند از remember
API برای ذخیره یک شی در حافظه استفاده کنند. مقداری که با remember
محاسبه می شود در ترکیب اولیه در Composition ذخیره می شود و مقدار ذخیره شده در طول ترکیب مجدد برگردانده می شود. remember
می تواند برای ذخیره اشیاء تغییرپذیر و غیرقابل تغییر استفاده شود.
mutableStateOf
یک MutableState<T>
قابل مشاهده ایجاد می کند که یک نوع قابل مشاهده است که با زمان اجرا ترکیب شده است.
interface MutableState<T> : State<T> {
override var value: T
}
هر گونه تغییر در value
، ترکیب مجدد هر توابع ترکیبی که value
میخواند، انجام میدهد.
سه راه برای اعلام یک شی MutableState
در یک composable وجود دارد:
-
val mutableState = remember { mutableStateOf(default) }
-
var value by remember { mutableStateOf(default) }
-
val (value, setValue) = remember { mutableStateOf(default) }
این اعلان ها معادل هستند و به عنوان قند نحوی برای کاربردهای مختلف حالت ارائه می شوند. شما باید کدی را انتخاب کنید که راحتترین کد را در فایلی که مینویسید تولید کند.
دستور by
delegate به واردات زیر نیاز دارد:
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
میتوانید از مقدار به خاطر سپردهشده بهعنوان پارامتری برای ترکیبپذیریهای دیگر یا حتی بهعنوان منطق در عبارات برای تغییر اینکه کدام ترکیبپذیر نمایش داده میشوند، استفاده کنید. به عنوان مثال، اگر نمی خواهید پیام تبریک را در صورت خالی بودن نام نمایش دهید، از حالت در عبارت if
استفاده کنید:
@Composable fun HelloContent() { Column(modifier = Modifier.padding(16.dp)) { var name by remember { mutableStateOf("") } if (name.isNotEmpty()) { Text( text = "Hello, $name!", modifier = Modifier.padding(bottom = 8.dp), style = MaterialTheme.typography.bodyMedium ) } OutlinedTextField( value = name, onValueChange = { name = it }, label = { Text("Name") } ) } }
در حالی که remember
به شما کمک میکند حالت را در بین ترکیبهای مجدد حفظ کنید، وضعیت در تغییرات پیکربندی حفظ نمیشود. برای این کار باید از rememberSaveable
استفاده کنید. rememberSaveable
به طور خودکار هر مقداری را که می توان در یک Bundle
ذخیره کرد ذخیره می کند. برای مقادیر دیگر، میتوانید یک شی محافظ سفارشی ارسال کنید.
سایر انواع ایالت های پشتیبانی شده
نوشتن نیازی به استفاده از MutableState<T>
برای نگه داشتن حالت ندارد. از دیگر انواع قابل مشاهده پشتیبانی می کند. قبل از خواندن یک نوع قابل مشاهده دیگر در Compose، باید آن را به State<T>
تبدیل کنید تا وقتی که حالت تغییر می کند، composable ها بتوانند به طور خودکار دوباره ترکیب شوند.
کشتی هایی با توابع برای ایجاد State<T>
از انواع معمولی قابل مشاهده که در برنامه های Android استفاده می شود بنویسید. قبل از استفاده از این ادغام ها، مصنوع(های) مناسب را مطابق زیر اضافه کنید:
Flow
:collectAsStateWithLifecycle()
collectAsStateWithLifecycle()
مقادیر را از یکFlow
به روشی آگاه از چرخه زندگی جمعآوری میکند و به برنامه شما اجازه میدهد منابع برنامه را حفظ کند. این نشان دهنده آخرین مقدار منتشر شده ازState
Compose است. از این API به عنوان روش توصیه شده برای جمع آوری جریان ها در برنامه های Android استفاده کنید.وابستگی زیر در فایل
build.gradle
لازم است (باید 2.6.0-beta01 یا جدیدتر باشد):
کاتلین
dependencies {
...
implementation("androidx.lifecycle:lifecycle-runtime-compose:2.8.7")
}
شیار
dependencies {
...
implementation "androidx.lifecycle:lifecycle-runtime-compose:2.8.7"
}
collectAsState
شبیهcollectAsStateWithLifecycle
است، زیرا مقادیر یکFlow
را نیز جمع آوری می کند و آن را بهState
Compose تبدیل می کند.به جای
collectAsStateWithLifecycle
، که فقط برای اندروید است، ازcollectAsState
برای کدهای پلتفرم آگنوستیک استفاده کنید.وابستگی های اضافی برای
collectAsState
لازم نیست، زیرا درcompose-runtime
در دسترس است.observeAsState()
شروع به مشاهده اینLiveData
می کند و مقادیر آن را از طریقState
نشان می دهد.وابستگی زیر در فایل
build.gradle
مورد نیاز است:
کاتلین
dependencies {
...
implementation("androidx.compose.runtime:runtime-livedata:1.8.1")
}
شیار
dependencies {
...
implementation "androidx.compose.runtime:runtime-livedata:1.8.1"
}
subscribeAsState()
توابع پسوندی هستند که جریانهای واکنشی RxJava2 (به عنوان مثالSingle
,Observable
,Completable
) را به ComposeState
تبدیل می کنند.وابستگی زیر در فایل
build.gradle
مورد نیاز است:
کاتلین
dependencies {
...
implementation("androidx.compose.runtime:runtime-rxjava2:1.8.1")
}
شیار
dependencies {
...
implementation "androidx.compose.runtime:runtime-rxjava2:1.8.1"
}
subscribeAsState()
توابع پسوندی هستند که جریانهای واکنشی RxJava3 (به عنوان مثالSingle
,Observable
,Completable
) را به ComposeState
تبدیل می کنند.وابستگی زیر در فایل
build.gradle
مورد نیاز است:
کاتلین
dependencies {
...
implementation("androidx.compose.runtime:runtime-rxjava3:1.8.1")
}
شیار
dependencies {
...
implementation "androidx.compose.runtime:runtime-rxjava3:1.8.1"
}
دولتی در مقابل بی تابعیتی
یک Composable که از remember
برای ذخیره یک شی استفاده میکند، حالت داخلی ایجاد میکند و حالت composable را حالت میکند. HelloContent
نمونه ای از یک حالت ترکیبی است زیرا وضعیت name
خود را در داخل نگه می دارد و تغییر می دهد. این می تواند در مواقعی مفید باشد که تماس گیرنده نیازی به کنترل حالت ندارد و می تواند بدون نیاز به مدیریت وضعیت خود از آن استفاده کند. با این حال، ترکیبات با حالت داخلی تمایل کمتری برای استفاده مجدد دارند و آزمایش آنها سخت تر است.
ترکیبپذیر بدون حالت، ترکیبپذیری است که هیچ حالتی ندارد. یک راه آسان برای دستیابی به حالت بدون تابعیت استفاده از بالابرهای دولتی است.
همانطور که شما قابلیتهای قابل استفاده مجدد را توسعه میدهید، اغلب میخواهید هم یک نسخه حالت دار و هم یک نسخه بدون حالت از یک قابلیت ترکیبسازی را در معرض نمایش قرار دهید. نسخه Stateful برای تماسگیرندگانی که به وضعیت اهمیتی نمیدهند مناسب است و نسخه بدون حالت برای تماسگیرندگانی که نیاز به کنترل یا بالا بردن وضعیت دارند، ضروری است.
بالابر دولتی
بالا بردن حالت در Compose الگویی از حرکت حالت به فراخوان کننده یک Composable برای ایجاد حالت Composable بدون حالت است. الگوی کلی برای بالا بردن حالت در Jetpack Compose جایگزینی متغیر حالت با دو پارامتر است:
-
value: T
: مقدار فعلی برای نمایش -
onValueChange: (T) -> Unit
: رویدادی که درخواست تغییر مقدار میکند، جایی کهT
مقدار جدید پیشنهادی است.
با این حال، شما محدود به onValueChange
نیستید. اگر رویدادهای خاص تری برای ترکیب بندی مناسب هستند، باید آنها را با استفاده از لامبدا تعریف کنید.
حالتی که به این روش بالا می رود دارای چند ویژگی مهم است:
- منبع منفرد حقیقت: با جابجایی حالت به جای تکرار آن، اطمینان حاصل می کنیم که تنها یک منبع حقیقت وجود دارد. این به جلوگیری از اشکالات کمک می کند.
- کپسوله شده: فقط ترکیبپذیرهای حالت دار میتوانند حالت خود را تغییر دهند. کاملا داخلیه
- قابل اشتراکگذاری: حالت Hoisted را میتوان با چندین ترکیب قابل اشتراکگذاری به اشتراک گذاشت. اگر میخواهید
name
با یک ترکیب متفاوت بخوانید، بالا بردن این امکان را به شما میدهد. - قابل رهگیری: تماس گیرندگان با قابلیت های ترکیبی بدون حالت می توانند تصمیم بگیرند که رویدادها را قبل از تغییر حالت نادیده بگیرند یا تغییر دهند.
- Decoupled: حالت برای ترکیبات بدون حالت ممکن است در هر جایی ذخیره شود. برای مثال، اکنون امکان انتقال
name
بهViewModel
وجود دارد.
در مورد مثال، name
و onValueChange
را از HelloContent
استخراج میکنید و آنها را به بالای درخت به یک HelloScreen
که HelloContent
را فراخوانی میکند منتقل میکنید.
@Composable fun HelloScreen() { var name by rememberSaveable { mutableStateOf("") } HelloContent(name = name, onNameChange = { name = it }) } @Composable fun HelloContent(name: String, onNameChange: (String) -> Unit) { Column(modifier = Modifier.padding(16.dp)) { Text( text = "Hello, $name", modifier = Modifier.padding(bottom = 8.dp), style = MaterialTheme.typography.bodyMedium ) OutlinedTextField(value = name, onValueChange = onNameChange, label = { Text("Name") }) } }
با بالا بردن حالت از HelloContent
، استدلال در مورد ترکیبپذیر، استفاده مجدد از آن در موقعیتهای مختلف و آزمایش آسانتر است. HelloContent
از نحوه ذخیره وضعیت آن جدا شده است. جداسازی به این معنی است که اگر HelloScreen
تغییر دهید یا جایگزین کنید، لازم نیست نحوه اجرای HelloContent
را تغییر دهید.

الگویی که در آن حالت پایین میآید و رویدادها بالا میروند، جریان دادههای یک طرفه نامیده میشود. در این حالت، وضعیت از HelloScreen
به HelloContent
پایین میآید و رویدادها از HelloContent
به HelloScreen
بالا میروند. با دنبال کردن جریان دادههای یکطرفه، میتوانید ترکیبپذیرهایی را که حالت نمایش در رابط کاربری را نشان میدهند از بخشهایی از برنامه خود که ذخیره میکنند و حالت را تغییر میدهند جدا کنید.
برای کسب اطلاعات بیشتر به صفحه ایالت کجا باید بالا برید مراجعه کنید.
در حال بازیابی حالت در Compose
API rememberSaveable
برای remember
رفتار مشابهی دارد زیرا حالت را در بین ترکیببندیهای مجدد و همچنین در سراسر فعالیت یا بازآفرینی فرآیند با استفاده از مکانیسم حالت نمونه ذخیره شده حفظ میکند. به عنوان مثال، این اتفاق می افتد، زمانی که صفحه نمایش چرخانده می شود.
راه های ذخیره سازی حالت
تمام انواع دادههایی که به Bundle
اضافه میشوند بهطور خودکار ذخیره میشوند. اگر می خواهید چیزی را ذخیره کنید که نمی تواند به Bundle
اضافه شود، چندین گزینه وجود دارد.
بسته بندی کنید
ساده ترین راه حل اضافه کردن حاشیه نویسی @Parcelize
به شی است. شیء قابل بسته بندی می شود و می توان آن را باندل کرد. به عنوان مثال، این کد یک نوع داده City
parcelable می سازد و آن را در حالت ذخیره می کند.
@Parcelize data class City(val name: String, val country: String) : Parcelable @Composable fun CityScreen() { var selectedCity = rememberSaveable { mutableStateOf(City("Madrid", "Spain")) } }
MapSaver
اگر به دلایلی @Parcelize
مناسب نیست، می توانید از mapSaver
برای تعریف قانون خود برای تبدیل یک شی به مجموعه ای از مقادیر استفاده کنید که سیستم می تواند در Bundle
ذخیره کند.
data class City(val name: String, val country: String) val CitySaver = run { val nameKey = "Name" val countryKey = "Country" mapSaver( save = { mapOf(nameKey to it.name, countryKey to it.country) }, restore = { City(it[nameKey] as String, it[countryKey] as String) } ) } @Composable fun CityScreen() { var selectedCity = rememberSaveable(stateSaver = CitySaver) { mutableStateOf(City("Madrid", "Spain")) } }
ListSaver
برای جلوگیری از نیاز به تعریف کلیدها برای نقشه، می توانید listSaver
نیز استفاده کنید و از شاخص های آن به عنوان کلید استفاده کنید:
data class City(val name: String, val country: String) val CitySaver = listSaver<City, Any>( save = { listOf(it.name, it.country) }, restore = { City(it[0] as String, it[1] as String) } ) @Composable fun CityScreen() { var selectedCity = rememberSaveable(stateSaver = CitySaver) { mutableStateOf(City("Madrid", "Spain")) } }
دارندگان ایالت در Compose
بالا بردن حالت ساده را می توان در خود توابع ترکیبی مدیریت کرد. با این حال، اگر مقدار حالت برای پیگیری افزایش یابد، یا منطقی که باید در توابع ترکیبپذیر انجام شود، کار خوبی است که مسئولیتهای منطقی و حالت را به کلاسهای دیگر واگذار کنید: دارندگان حالت .
برای کسب اطلاعات بیشتر، بالا بردن حالت را در مستندات Compose یا به طور کلیتر، صفحه دارندگان State و UI State را در راهنمای معماری ببینید.
هنگامی که کلیدها تغییر می کنند، محاسبات را به خاطر بسپارید
remember
API اغلب همراه با MutableState
استفاده می شود:
var name by remember { mutableStateOf("") }
در اینجا، استفاده از تابع remember
باعث میشود که مقدار MutableState
در ترکیب مجدد باقی بماند.
به طور کلی، remember
که یک پارامتر لامبدا calculation
می کند. هنگامی که remember
برای اولین بار اجرا می شود، calculation
لامبدا را فراخوانی می کند و نتیجه آن را ذخیره می کند. در طول ترکیب مجدد، remember
مقداری را که آخرین بار ذخیره شده است، برمی گرداند.
جدا از حالت کش، میتوانید از remember
برای ذخیره هر شی یا نتیجه عملیاتی در Composition استفاده کنید که مقداردهی اولیه یا محاسبه آن گران است. ممکن است نخواهید این محاسبه را در هر ترکیب مجدد تکرار کنید. یک مثال ایجاد این شی ShaderBrush
است که یک عملیات گران قیمت است:
val brush = remember { ShaderBrush( BitmapShader( ImageBitmap.imageResource(res, avatarRes).asAndroidBitmap(), Shader.TileMode.REPEAT, Shader.TileMode.REPEAT ) ) }
remember
مقدار را تا زمانی که از Composition خارج شود ذخیره می کند. با این حال، راهی برای باطل کردن مقدار ذخیره شده وجود دارد. remember
API نیز یک پارامتر key
یا keys
را می گیرد. اگر هر یک از این کلیدها تغییر کرد، دفعه بعد که تابع دوباره ترکیب شد ، remember
که حافظه پنهان را باطل می کند و بلوک لامبدا محاسبه را دوباره اجرا می کند . این مکانیسم به شما امکان کنترل طول عمر یک شی در Composition را می دهد. محاسبه تا زمانی که ورودیها تغییر نکنند معتبر میماند، نه تا زمانی که مقدار به خاطر سپرده شده از ترکیب خارج شود.
مثال های زیر نحوه عملکرد این مکانیسم را نشان می دهد.
در این قطعه، ShaderBrush
ایجاد شده و به عنوان رنگ پسزمینه یک Box
composable استفاده میشود. remember
نمونه ShaderBrush
ذخیره می کند زیرا همانطور که قبلا توضیح داده شد، بازسازی آن گران است. remember
که avatarRes
به عنوان پارامتر key1
می گیرد که تصویر پس زمینه انتخاب شده است. اگر avatarRes
تغییر کند، قلم مو با تصویر جدید دوباره ترکیب میشود و دوباره روی Box
اعمال میشود. این می تواند زمانی رخ دهد که کاربر تصویر دیگری را به عنوان پس زمینه از یک انتخابگر انتخاب کند.
@Composable private fun BackgroundBanner( @DrawableRes avatarRes: Int, modifier: Modifier = Modifier, res: Resources = LocalContext.current.resources ) { val brush = remember(key1 = avatarRes) { ShaderBrush( BitmapShader( ImageBitmap.imageResource(res, avatarRes).asAndroidBitmap(), Shader.TileMode.REPEAT, Shader.TileMode.REPEAT ) ) } Box( modifier = modifier.background(brush) ) { /* ... */ } }
در قطعه بعدی، state به کلاس دارنده حالت ساده MyAppState
بالا می رود. این یک تابع rememberMyAppState
را برای مقداردهی اولیه یک نمونه از کلاس با استفاده از remember
نمایش می دهد. نمایش چنین توابعی برای ایجاد نمونه ای که از ترکیب مجدد جان سالم به در می برد، یک الگوی رایج در Compose است. تابع rememberMyAppState
windowSizeClass
دریافت می کند که به عنوان پارامتر key
برای remember
عمل می کند. اگر این پارامتر تغییر کند، برنامه باید کلاس دارنده حالت ساده را با آخرین مقدار دوباره ایجاد کند. برای مثال، اگر کاربر دستگاه را بچرخاند، ممکن است این اتفاق بیفتد.
@Composable private fun rememberMyAppState( windowSizeClass: WindowSizeClass ): MyAppState { return remember(windowSizeClass) { MyAppState(windowSizeClass) } } @Stable class MyAppState( private val windowSizeClass: WindowSizeClass ) { /* ... */ }
Compose از پیاده سازی برابرهای کلاس برای تصمیم گیری در مورد تغییر یک کلید و بی اعتبار کردن مقدار ذخیره شده استفاده می کند.
وضعیت ذخیره با کلیدهای فراتر از ترکیب مجدد
API rememberSaveable
remember
است که می تواند داده ها را در یک Bundle
ذخیره کند. این API به حالت اجازه می دهد تا نه تنها از ترکیب مجدد، بلکه از فعالیت های تفریحی و مرگ فرآیند آغاز شده توسط سیستم نیز زنده بماند. rememberSaveable
پارامترهای input
را برای همان هدفی که remember
keys
دریافت دریافت می کند، دریافت می کند. هنگامی که هر یک از ورودی ها تغییر می کند، حافظه پنهان باطل می شود . دفعه بعد که تابع دوباره ترکیب می شود، rememberSaveable
بلوک لامبدا محاسبه را دوباره اجرا می کند.
در مثال زیر، rememberSaveable
userTypedQuery
ذخیره می کند تا زمانی که typedQuery
تغییر کند:
var userTypedQuery by rememberSaveable(typedQuery, stateSaver = TextFieldValue.Saver) { mutableStateOf( TextFieldValue(text = typedQuery, selection = TextRange(typedQuery.length)) ) }
بیشتر بدانید
برای کسب اطلاعات بیشتر در مورد State و Jetpack Compose، به منابع اضافی زیر مراجعه کنید.
نمونه ها
Codelabs
ویدیوها
وبلاگ ها
{% کلمه به کلمه %}برای شما توصیه می شود
- توجه: وقتی جاوا اسکریپت خاموش است، متن پیوند نمایش داده می شود
- معماری UI Compose شما
- حالت رابط کاربری را در Compose ذخیره کنید
- عوارض جانبی در Compose
حالت در برنامه هر مقداری است که می تواند در طول زمان تغییر کند. این یک تعریف بسیار گسترده است و همه چیز را از یک پایگاه داده اتاق گرفته تا یک متغیر در یک کلاس را در بر می گیرد.
همه برنامه های اندروید وضعیت را به کاربر نمایش می دهند. چند نمونه از حالت در برنامه های اندروید:
- یک نوار اسنک که نشان می دهد چه زمانی اتصال شبکه نمی تواند برقرار شود.
- یک پست وبلاگ و نظرات مرتبط.
- انیمیشنها را روی دکمههایی که وقتی کاربر روی آنها کلیک میکند پخش میشوند.
- برچسب هایی که کاربر می تواند روی یک تصویر بکشد.
Jetpack Compose به شما کمک میکند در مورد مکان و نحوه ذخیره و استفاده از وضعیت در یک برنامه Android صریح باشید. این راهنما بر ارتباط بین state و composable ها، و API هایی که Jetpack Compose برای کار راحت تر با state ارائه می دهد، تمرکز دارد.
حالت و ترکیب
Compose اعلانی است و به این ترتیب تنها راه برای به روز رسانی آن فراخوانی همان composable با آرگومان های جدید است. این آرگومان ها نمایشی از وضعیت UI هستند. هر زمان که وضعیتی به روز می شود، ترکیب مجدد صورت می گیرد. در نتیجه، چیزهایی مانند TextField
به طور خودکار مانند نماهای ضروری مبتنی بر XML به روز نمی شوند. به یک composable باید به صراحت وضعیت جدید گفته شود تا مطابق آن به روز شود.
@Composable private fun HelloContent() { Column(modifier = Modifier.padding(16.dp)) { Text( text = "Hello!", modifier = Modifier.padding(bottom = 8.dp), style = MaterialTheme.typography.bodyMedium ) OutlinedTextField( value = "", onValueChange = { }, label = { Text("Name") } ) } }
اگر این را اجرا کنید و سعی کنید متن را وارد کنید، خواهید دید که هیچ اتفاقی نمی افتد. دلیلش این است که TextField
خودش را به روز نمی کند - زمانی که پارامتر value
آن تغییر می کند، به روز می شود. این به دلیل نحوه کار ترکیب و ترکیب مجدد در Compose است.
برای کسب اطلاعات بیشتر در مورد ترکیب اولیه و ترکیب مجدد، به تفکر در نوشتن مراجعه کنید.
حالت در ترکیبات
توابع Composable می توانند از remember
API برای ذخیره یک شی در حافظه استفاده کنند. مقداری که با remember
محاسبه می شود در ترکیب اولیه در Composition ذخیره می شود و مقدار ذخیره شده در طول ترکیب مجدد برگردانده می شود. remember
می تواند برای ذخیره اشیاء تغییرپذیر و غیرقابل تغییر استفاده شود.
mutableStateOf
یک MutableState<T>
قابل مشاهده ایجاد می کند که یک نوع قابل مشاهده است که با زمان اجرا ترکیب شده است.
interface MutableState<T> : State<T> {
override var value: T
}
هر گونه تغییر در value
، ترکیب مجدد هر توابع ترکیبی که value
میخواند، انجام میدهد.
سه راه برای اعلام یک شی MutableState
در یک composable وجود دارد:
-
val mutableState = remember { mutableStateOf(default) }
-
var value by remember { mutableStateOf(default) }
-
val (value, setValue) = remember { mutableStateOf(default) }
این اعلان ها معادل هستند و به عنوان قند نحوی برای کاربردهای مختلف حالت ارائه می شوند. شما باید کدی را انتخاب کنید که راحتترین کد را در فایلی که مینویسید تولید کند.
دستور by
delegate به واردات زیر نیاز دارد:
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
میتوانید از مقدار به خاطر سپردهشده بهعنوان پارامتری برای ترکیبپذیریهای دیگر یا حتی بهعنوان منطق در عبارات برای تغییر اینکه کدام ترکیبپذیر نمایش داده میشوند، استفاده کنید. به عنوان مثال، اگر نمی خواهید پیام تبریک را در صورت خالی بودن نام نمایش دهید، از حالت در عبارت if
استفاده کنید:
@Composable fun HelloContent() { Column(modifier = Modifier.padding(16.dp)) { var name by remember { mutableStateOf("") } if (name.isNotEmpty()) { Text( text = "Hello, $name!", modifier = Modifier.padding(bottom = 8.dp), style = MaterialTheme.typography.bodyMedium ) } OutlinedTextField( value = name, onValueChange = { name = it }, label = { Text("Name") } ) } }
در حالی که remember
به شما کمک میکند حالت را در بین ترکیبهای مجدد حفظ کنید، وضعیت در تغییرات پیکربندی حفظ نمیشود. برای این کار باید از rememberSaveable
استفاده کنید. rememberSaveable
به طور خودکار هر مقداری را که می توان در یک Bundle
ذخیره کرد ذخیره می کند. برای مقادیر دیگر، میتوانید یک شی محافظ سفارشی ارسال کنید.
سایر انواع ایالت های پشتیبانی شده
نوشتن نیازی به استفاده از MutableState<T>
برای نگه داشتن حالت ندارد. از دیگر انواع قابل مشاهده پشتیبانی می کند. قبل از خواندن یک نوع قابل مشاهده دیگر در Compose، باید آن را به State<T>
تبدیل کنید تا وقتی که حالت تغییر می کند، composable ها بتوانند به طور خودکار دوباره ترکیب شوند.
کشتی هایی با توابع برای ایجاد State<T>
از انواع معمولی قابل مشاهده که در برنامه های Android استفاده می شود بنویسید. قبل از استفاده از این ادغام ها، مصنوع(های) مناسب را مطابق زیر اضافه کنید:
Flow
:collectAsStateWithLifecycle()
collectAsStateWithLifecycle()
مقادیر را از یکFlow
به روشی آگاه از چرخه زندگی جمعآوری میکند و به برنامه شما اجازه میدهد منابع برنامه را حفظ کند. این نشان دهنده آخرین مقدار منتشر شده ازState
Compose است. از این API به عنوان روش توصیه شده برای جمع آوری جریان ها در برنامه های Android استفاده کنید.وابستگی زیر در فایل
build.gradle
لازم است (باید 2.6.0-beta01 یا جدیدتر باشد):
کاتلین
dependencies {
...
implementation("androidx.lifecycle:lifecycle-runtime-compose:2.8.7")
}
شیار
dependencies {
...
implementation "androidx.lifecycle:lifecycle-runtime-compose:2.8.7"
}
collectAsState
شبیهcollectAsStateWithLifecycle
است، زیرا مقادیر یکFlow
را نیز جمع آوری می کند و آن را بهState
Compose تبدیل می کند.به جای
collectAsStateWithLifecycle
، که فقط برای اندروید است، ازcollectAsState
برای کدهای پلتفرم آگنوستیک استفاده کنید.وابستگی های اضافی برای
collectAsState
لازم نیست، زیرا درcompose-runtime
در دسترس است.observeAsState()
شروع به مشاهده اینLiveData
می کند و مقادیر آن را از طریقState
نشان می دهد.وابستگی زیر در فایل
build.gradle
مورد نیاز است:
کاتلین
dependencies {
...
implementation("androidx.compose.runtime:runtime-livedata:1.8.1")
}
شیار
dependencies {
...
implementation "androidx.compose.runtime:runtime-livedata:1.8.1"
}
subscribeAsState()
توابع پسوندی هستند که جریانهای واکنشی RxJava2 (به عنوان مثالSingle
,Observable
,Completable
) را به ComposeState
تبدیل می کنند.وابستگی زیر در فایل
build.gradle
مورد نیاز است:
کاتلین
dependencies {
...
implementation("androidx.compose.runtime:runtime-rxjava2:1.8.1")
}
شیار
dependencies {
...
implementation "androidx.compose.runtime:runtime-rxjava2:1.8.1"
}
subscribeAsState()
توابع پسوندی هستند که جریانهای واکنشی RxJava3 (به عنوان مثالSingle
,Observable
,Completable
) را به ComposeState
تبدیل می کنند.وابستگی زیر در فایل
build.gradle
مورد نیاز است:
کاتلین
dependencies {
...
implementation("androidx.compose.runtime:runtime-rxjava3:1.8.1")
}
شیار
dependencies {
...
implementation "androidx.compose.runtime:runtime-rxjava3:1.8.1"
}
دولتی در مقابل بی تابعیتی
یک Composable که از remember
برای ذخیره یک شی استفاده میکند، حالت داخلی ایجاد میکند و حالت composable را حالت میکند. HelloContent
نمونه ای از یک حالت ترکیبی است زیرا وضعیت name
خود را در داخل نگه می دارد و تغییر می دهد. این می تواند در مواقعی مفید باشد که تماس گیرنده نیازی به کنترل حالت ندارد و می تواند بدون نیاز به مدیریت وضعیت خود از آن استفاده کند. با این حال، ترکیبات با حالت داخلی تمایل کمتری برای استفاده مجدد دارند و آزمایش آنها سخت تر است.
ترکیبپذیر بدون حالت، ترکیبپذیری است که هیچ حالتی ندارد. یک راه آسان برای دستیابی به حالت بدون تابعیت استفاده از بالابرهای دولتی است.
همانطور که شما قابلیتهای قابل استفاده مجدد را توسعه میدهید، اغلب میخواهید هم یک نسخه حالت دار و هم یک نسخه بدون حالت از یک قابلیت ترکیبسازی را در معرض نمایش قرار دهید. نسخه Stateful برای تماسگیرندگانی که به وضعیت اهمیتی نمیدهند مناسب است و نسخه بدون حالت برای تماسگیرندگانی که نیاز به کنترل یا بالا بردن وضعیت دارند، ضروری است.
بالابر دولتی
بالا بردن حالت در Compose الگویی از حرکت حالت به فراخوان کننده یک Composable برای ایجاد حالت Composable بدون حالت است. الگوی کلی برای بالا بردن حالت در Jetpack Compose جایگزینی متغیر حالت با دو پارامتر است:
-
value: T
: مقدار فعلی برای نمایش -
onValueChange: (T) -> Unit
: رویدادی که درخواست تغییر مقدار میکند، جایی کهT
مقدار جدید پیشنهادی است.
با این حال، شما محدود به onValueChange
نیستید. اگر رویدادهای خاص تری برای ترکیب بندی مناسب هستند، باید آنها را با استفاده از لامبدا تعریف کنید.
حالتی که به این روش بالا می رود دارای چند ویژگی مهم است:
- منبع منفرد حقیقت: با جابجایی حالت به جای تکرار آن، اطمینان حاصل می کنیم که تنها یک منبع حقیقت وجود دارد. این به جلوگیری از اشکالات کمک می کند.
- کپسوله شده: فقط ترکیبپذیرهای حالت دار میتوانند حالت خود را تغییر دهند. کاملا داخلیه
- قابل اشتراکگذاری: حالت Hoisted را میتوان با چندین ترکیب قابل اشتراکگذاری به اشتراک گذاشت. اگر میخواهید
name
با یک ترکیب متفاوت بخوانید، بالا بردن این امکان را به شما میدهد. - قابل رهگیری: تماس گیرندگان با قابلیت های ترکیبی بدون حالت می توانند تصمیم بگیرند که رویدادها را قبل از تغییر حالت نادیده بگیرند یا تغییر دهند.
- Decoupled: حالت برای ترکیبات بدون حالت ممکن است در هر جایی ذخیره شود. برای مثال، اکنون امکان انتقال
name
بهViewModel
وجود دارد.
در مورد مثال، name
و onValueChange
را از HelloContent
استخراج میکنید و آنها را به بالای درخت به یک HelloScreen
که HelloContent
را فراخوانی میکند منتقل میکنید.
@Composable fun HelloScreen() { var name by rememberSaveable { mutableStateOf("") } HelloContent(name = name, onNameChange = { name = it }) } @Composable fun HelloContent(name: String, onNameChange: (String) -> Unit) { Column(modifier = Modifier.padding(16.dp)) { Text( text = "Hello, $name", modifier = Modifier.padding(bottom = 8.dp), style = MaterialTheme.typography.bodyMedium ) OutlinedTextField(value = name, onValueChange = onNameChange, label = { Text("Name") }) } }
با بالا بردن حالت از HelloContent
، استدلال در مورد ترکیبپذیر، استفاده مجدد از آن در موقعیتهای مختلف و آزمایش آسانتر است. HelloContent
از نحوه ذخیره وضعیت آن جدا شده است. جداسازی به این معنی است که اگر HelloScreen
تغییر دهید یا جایگزین کنید، لازم نیست نحوه اجرای HelloContent
را تغییر دهید.

الگویی که در آن حالت پایین میآید و رویدادها بالا میروند، جریان دادههای یک طرفه نامیده میشود. در این حالت، وضعیت از HelloScreen
به HelloContent
پایین میآید و رویدادها از HelloContent
به HelloScreen
بالا میروند. با دنبال کردن جریان دادههای یکطرفه، میتوانید ترکیبپذیرهایی را که حالت نمایش در رابط کاربری را نشان میدهند از بخشهایی از برنامه خود که ذخیره میکنند و حالت را تغییر میدهند جدا کنید.
برای کسب اطلاعات بیشتر به صفحه ایالت کجا باید بالا برید مراجعه کنید.
در حال بازیابی حالت در Compose
API rememberSaveable
برای remember
رفتار مشابهی دارد زیرا حالت را در بین ترکیببندیهای مجدد و همچنین در سراسر فعالیت یا بازآفرینی فرآیند با استفاده از مکانیسم حالت نمونه ذخیره شده حفظ میکند. به عنوان مثال، این اتفاق می افتد، زمانی که صفحه نمایش چرخانده می شود.
راه های ذخیره سازی حالت
تمام انواع دادههایی که به Bundle
اضافه میشوند بهطور خودکار ذخیره میشوند. اگر می خواهید چیزی را ذخیره کنید که نمی تواند به Bundle
اضافه شود، چندین گزینه وجود دارد.
بسته بندی کنید
ساده ترین راه حل اضافه کردن حاشیه نویسی @Parcelize
به شی است. شیء قابل بسته بندی می شود و می توان آن را باندل کرد. به عنوان مثال، این کد یک نوع داده City
parcelable می سازد و آن را در حالت ذخیره می کند.
@Parcelize data class City(val name: String, val country: String) : Parcelable @Composable fun CityScreen() { var selectedCity = rememberSaveable { mutableStateOf(City("Madrid", "Spain")) } }
MapSaver
اگر به دلایلی @Parcelize
مناسب نیست، می توانید از mapSaver
برای تعریف قانون خود برای تبدیل یک شی به مجموعه ای از مقادیر استفاده کنید که سیستم می تواند در Bundle
ذخیره کند.
data class City(val name: String, val country: String) val CitySaver = run { val nameKey = "Name" val countryKey = "Country" mapSaver( save = { mapOf(nameKey to it.name, countryKey to it.country) }, restore = { City(it[nameKey] as String, it[countryKey] as String) } ) } @Composable fun CityScreen() { var selectedCity = rememberSaveable(stateSaver = CitySaver) { mutableStateOf(City("Madrid", "Spain")) } }
ListSaver
برای جلوگیری از نیاز به تعریف کلیدها برای نقشه، می توانید listSaver
نیز استفاده کنید و از شاخص های آن به عنوان کلید استفاده کنید:
data class City(val name: String, val country: String) val CitySaver = listSaver<City, Any>( save = { listOf(it.name, it.country) }, restore = { City(it[0] as String, it[1] as String) } ) @Composable fun CityScreen() { var selectedCity = rememberSaveable(stateSaver = CitySaver) { mutableStateOf(City("Madrid", "Spain")) } }
دارندگان ایالت در Compose
بالا بردن حالت ساده را می توان در خود توابع ترکیبی مدیریت کرد. با این حال، اگر مقدار حالت برای پیگیری افزایش یابد، یا منطقی که باید در توابع ترکیبپذیر انجام شود، کار خوبی است که مسئولیتهای منطقی و حالت را به کلاسهای دیگر واگذار کنید: دارندگان حالت .
برای کسب اطلاعات بیشتر، بالا بردن حالت را در مستندات Compose یا به طور کلیتر، صفحه دارندگان State و UI State را در راهنمای معماری ببینید.
هنگامی که کلیدها تغییر می کنند، محاسبات را به خاطر بسپارید
remember
API اغلب همراه با MutableState
استفاده می شود:
var name by remember { mutableStateOf("") }
در اینجا، استفاده از تابع remember
باعث میشود که مقدار MutableState
در ترکیب مجدد باقی بماند.
به طور کلی، remember
که یک پارامتر لامبدا calculation
می کند. هنگامی که remember
برای اولین بار اجرا می شود، calculation
لامبدا را فراخوانی می کند و نتیجه آن را ذخیره می کند. در طول ترکیب مجدد، remember
مقداری را که آخرین بار ذخیره شده است، برمی گرداند.
جدا از حالت کش، میتوانید از remember
برای ذخیره هر شی یا نتیجه عملیاتی در Composition استفاده کنید که مقداردهی اولیه یا محاسبه آن گران است. ممکن است نخواهید این محاسبه را در هر ترکیب مجدد تکرار کنید. یک مثال ایجاد این شی ShaderBrush
است که یک عملیات گران قیمت است:
val brush = remember { ShaderBrush( BitmapShader( ImageBitmap.imageResource(res, avatarRes).asAndroidBitmap(), Shader.TileMode.REPEAT, Shader.TileMode.REPEAT ) ) }
remember
مقدار را تا زمانی که از Composition خارج شود ذخیره می کند. با این حال، راهی برای باطل کردن مقدار ذخیره شده وجود دارد. remember
API نیز یک پارامتر key
یا keys
را می گیرد. اگر هر یک از این کلیدها تغییر کرد، دفعه بعد که تابع دوباره ترکیب شد ، remember
که حافظه پنهان را باطل می کند و بلوک لامبدا محاسبه را دوباره اجرا می کند . این مکانیسم به شما امکان کنترل طول عمر یک شی در Composition را می دهد. محاسبه تا زمانی که ورودیها تغییر نکنند معتبر میماند، نه تا زمانی که مقدار به خاطر سپرده شده از ترکیب خارج شود.
مثال های زیر نحوه عملکرد این مکانیسم را نشان می دهد.
در این قطعه، ShaderBrush
ایجاد شده و به عنوان رنگ پسزمینه یک Box
composable استفاده میشود. remember
نمونه ShaderBrush
ذخیره می کند زیرا همانطور که قبلا توضیح داده شد، بازسازی آن گران است. remember
که avatarRes
به عنوان پارامتر key1
می گیرد که تصویر پس زمینه انتخاب شده است. اگر avatarRes
تغییر کند، قلم مو با تصویر جدید دوباره ترکیب میشود و دوباره روی Box
اعمال میشود. این می تواند زمانی رخ دهد که کاربر تصویر دیگری را به عنوان پس زمینه از یک انتخابگر انتخاب کند.
@Composable private fun BackgroundBanner( @DrawableRes avatarRes: Int, modifier: Modifier = Modifier, res: Resources = LocalContext.current.resources ) { val brush = remember(key1 = avatarRes) { ShaderBrush( BitmapShader( ImageBitmap.imageResource(res, avatarRes).asAndroidBitmap(), Shader.TileMode.REPEAT, Shader.TileMode.REPEAT ) ) } Box( modifier = modifier.background(brush) ) { /* ... */ } }
در قطعه بعدی، state به کلاس دارنده حالت ساده MyAppState
بالا می رود. این یک تابع rememberMyAppState
را برای مقداردهی اولیه یک نمونه از کلاس با استفاده از remember
نمایش می دهد. نمایش چنین توابعی برای ایجاد نمونه ای که از ترکیب مجدد جان سالم به در می برد، یک الگوی رایج در Compose است. تابع rememberMyAppState
windowSizeClass
دریافت می کند که به عنوان پارامتر key
برای remember
عمل می کند. اگر این پارامتر تغییر کند، برنامه باید کلاس دارنده حالت ساده را با آخرین مقدار دوباره ایجاد کند. برای مثال، اگر کاربر دستگاه را بچرخاند، ممکن است این اتفاق بیفتد.
@Composable private fun rememberMyAppState( windowSizeClass: WindowSizeClass ): MyAppState { return remember(windowSizeClass) { MyAppState(windowSizeClass) } } @Stable class MyAppState( private val windowSizeClass: WindowSizeClass ) { /* ... */ }
Compose از پیاده سازی برابرهای کلاس برای تصمیم گیری در مورد تغییر یک کلید و بی اعتبار کردن مقدار ذخیره شده استفاده می کند.
وضعیت ذخیره با کلیدهای فراتر از ترکیب مجدد
API rememberSaveable
remember
است که می تواند داده ها را در یک Bundle
ذخیره کند. این API به حالت اجازه می دهد تا نه تنها از ترکیب مجدد، بلکه از فعالیت های تفریحی و مرگ فرآیند آغاز شده توسط سیستم نیز زنده بماند. rememberSaveable
پارامترهای input
را برای همان هدفی که remember
keys
دریافت می کند ، دریافت می کند. هنگامی که هر یک از ورودی ها تغییر می کنند ، حافظه پنهان باطل می شود . دفعه بعد که عملکرد دوباره انجام می شود ، rememberSaveable
که قابل استفاده مجدد بلوک لامبدا محاسبه می شود.
در مثال زیر ، فروشگاه های قابل حمل userTypedQuery
rememberSaveable
تا زمانی که typedQuery
تغییر کند:
var userTypedQuery by rememberSaveable(typedQuery, stateSaver = TextFieldValue.Saver) { mutableStateOf( TextFieldValue(text = typedQuery, selection = TextRange(typedQuery.length)) ) }
بیشتر بدانید
برای کسب اطلاعات بیشتر در مورد Constate State و JetPack ، با منابع اضافی زیر مشورت کنید.
نمونه ها
Codelabs
ویدیوها
وبلاگ ها
{٪ کلمه ٪}برای شما توصیه می شود
- توجه: هنگام خاموش بودن جاوا اسکریپت ، متن پیوند نمایش داده می شود
- معماری UI آهنگسازی شما
- وضعیت UI را در آهنگسازی ذخیره کنید
- عوارض جانبی در آهنگسازی
حالت در یک برنامه هر ارزشی است که می تواند با گذشت زمان تغییر کند. این یک تعریف بسیار گسترده است و همه چیز را از یک پایگاه داده اتاق گرفته تا یک متغیر در یک کلاس در بر می گیرد.
همه برنامه های Android وضعیت را به کاربر نشان می دهند. چند نمونه از حالت در برنامه های Android:
- اسنکبر که نشان می دهد چه زمانی نمی توان اتصال شبکه برقرار کرد.
- یک پست وبلاگ و نظرات مرتبط.
- انیمیشن های ریپل روی دکمه هایی که وقتی کاربر روی آنها کلیک می کند بازی می کنند.
- برچسب هایی که کاربر می تواند در بالای یک تصویر ترسیم کند.
JetPack Compose به شما کمک می کند تا در مورد مکان و نحوه ذخیره و استفاده از حالت در یک برنامه Android صریح باشید. این راهنما به ارتباط بین حالت و ترکیبات و API هایی که Jetpack Compose ارائه می دهد برای کار راحت تر با حالت ارائه می دهد.
حالت و ترکیب
آهنگسازی اعلامی است و به همین ترتیب تنها راه به روزرسانی آن با فراخوانی همان ترکیب با استدلال های جدید است. این استدلال ها بازنمایی از دولت UI است. هر زمان که یک حالت به روز شود ، بازپرداخت صورت می گیرد. در نتیجه ، مواردی مانند TextField
به طور خودکار مانند آنچه در نماهای مبتنی بر XML انجام می شود به روز نمی شوند. یک ترکیب باید صریحاً به حالت جدید گفته شود تا بتواند بر این اساس به روز شود.
@Composable private fun HelloContent() { Column(modifier = Modifier.padding(16.dp)) { Text( text = "Hello!", modifier = Modifier.padding(bottom = 8.dp), style = MaterialTheme.typography.bodyMedium ) OutlinedTextField( value = "", onValueChange = { }, label = { Text("Name") } ) } }
اگر این کار را اجرا کنید و سعی کنید متن را وارد کنید ، می بینید که هیچ اتفاقی نمی افتد. به این دلیل است که TextField
خود را به روز نمی کند - وقتی پارامتر value
آن تغییر می کند ، به روز می شود. این به دلیل نحوه کار ترکیب و بازپرداخت در آهنگسازی است.
برای کسب اطلاعات بیشتر در مورد ترکیب اولیه و تجدید نظر ، به تفکر در آهنگسازی مراجعه کنید.
حالت در ترکیبات
توابع کامپوزیت می توانند از API remember
تا یک شی را در حافظه ذخیره کنید. مقداری محاسبه شده توسط remember
در طول ترکیب اولیه در ترکیب ذخیره می شود و مقدار ذخیره شده در طول بازپرداخت بازگردانده می شود. remember
می توانید برای ذخیره هر دو اشیاء قابل تغییر و تغییر ناپذیر استفاده کنید.
mutableStateOf
یک MutableState<T>
ایجاد می کند ، که یک نوع قابل مشاهده است که با زمان اجرای آهنگسازی یکپارچه شده است.
interface MutableState<T> : State<T> {
override var value: T
}
هرگونه تغییر در برنامه های value
، بازآفرینی از هر کارکرد ترکیب را که value
می خوانند ، می کند.
سه روش برای اعلام یک شیء MutableState
در یک ترکیب وجود دارد:
-
val mutableState = remember { mutableStateOf(default) }
-
var value by remember { mutableStateOf(default) }
-
val (value, setValue) = remember { mutableStateOf(default) }
این اعلامیه ها معادل هستند و به عنوان قند نحوی برای استفاده های مختلف دولت ارائه می شوند. شما باید یکی از مواردی را انتخاب کنید که ساده ترین کد خواندن را در آهنگسازی که می نویسید تولید می کند.
نحو by
نماینده به واردات زیر نیاز دارد:
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
شما می توانید از مقدار به یاد داشته باشید به عنوان یک پارامتر برای سایر آهنگسازان یا حتی به عنوان منطق در بیانیه ها برای تغییر کدام یک از ترکیبات نمایش داده می شود. به عنوان مثال ، اگر نمی خواهید در صورت خالی بودن نام ، تبریک را نمایش دهید ، از حالت در بیانیه if
استفاده کنید:
@Composable fun HelloContent() { Column(modifier = Modifier.padding(16.dp)) { var name by remember { mutableStateOf("") } if (name.isNotEmpty()) { Text( text = "Hello, $name!", modifier = Modifier.padding(bottom = 8.dp), style = MaterialTheme.typography.bodyMedium ) } OutlinedTextField( value = name, onValueChange = { name = it }, label = { Text("Name") } ) } }
در حالی که remember
به شما کمک می کند تا حالت را در بازپرداخت ها حفظ کنید ، دولت در سراسر تغییرات پیکربندی حفظ نمی شود. برای این کار ، شما باید از rememberSaveable
استفاده کنید. rememberSaveable
به طور خودکار هر مقداری را که می تواند در یک Bundle
ذخیره شود ، ذخیره می کند. برای مقادیر دیگر ، می توانید در یک شیء محافظ سفارشی عبور کنید.
سایر انواع پشتیبانی شده دولت
آهنگسازی نیازی به استفاده از MutableState<T>
برای نگه داشتن حالت ندارد. از انواع دیگر قابل مشاهده پشتیبانی می کند. قبل از خواندن نوع قابل مشاهده دیگری در آهنگسازی ، باید آن را به State<T>
تبدیل کنید تا در صورت تغییر حالت ، آهنگسازان بتوانند به طور خودکار دوباره درخواست کنند.
کشتی ها را با توابع برای ایجاد State<T>
از انواع قابل مشاهده متداول که در برنامه های اندرویدی استفاده می شود ، تهیه کنید. قبل از استفاده از این ادغام ها ، مصنوعات (های) مناسب را مطابق شکل زیر اضافه کنید:
Flow
:collectAsStateWithLifecycle()
collectAsStateWithLifecycle()
مقادیر را از یکFlow
به صورت آگاه از چرخه عمر جمع می کند و به برنامه شما اجازه می دهد تا منابع برنامه را حفظ کند. این نشان دهنده آخرین مقدار ساطع شده ازState
آهنگسازی است. از این API به عنوان روش توصیه شده برای جمع آوری جریان در برنامه های Android استفاده کنید.وابستگی زیر در پرونده
build.gradle
مورد نیاز است (باید 2.6.0-beta01 یا جدیدتر باشد):
کاتلین
dependencies {
...
implementation("androidx.lifecycle:lifecycle-runtime-compose:2.8.7")
}
شیار
dependencies {
...
implementation "androidx.lifecycle:lifecycle-runtime-compose:2.8.7"
}
collectAsState
شبیه بهcollectAsStateWithLifecycle
است ، زیرا مقادیر را از یکFlow
نیز جمع می کند و آن را بهState
آهنگسازی تبدیل می کند.به جای
collectAsStateWithLifecycle
، که فقط اندرویدی است ، ازcollectAsState
برای کد پلتفرم-آگنوستیک استفاده کنید.وابستگی های اضافی برای
collectAsState
لازم نیست ، زیرا درcompose-runtime
در دسترس است.observeAsState()
مشاهده اینLiveData
شروع می کند و ارزش های آن را از طریقState
نشان می دهد.وابستگی زیر در پرونده
build.gradle
مورد نیاز است:
کاتلین
dependencies {
...
implementation("androidx.compose.runtime:runtime-livedata:1.8.1")
}
شیار
dependencies {
...
implementation "androidx.compose.runtime:runtime-livedata:1.8.1"
}
subscribeAsState()
توابع پسوند هستند که جریانهای واکنشی rxjava2 (به عنوان مثالSingle
،Observable
،Completable
) را بهState
آهنگسازی تبدیل می کنند.وابستگی زیر در پرونده
build.gradle
مورد نیاز است:
کاتلین
dependencies {
...
implementation("androidx.compose.runtime:runtime-rxjava2:1.8.1")
}
شیار
dependencies {
...
implementation "androidx.compose.runtime:runtime-rxjava2:1.8.1"
}
subscribeAsState()
توابع پسوند هستند که جریانهای واکنشی Rxjava3 (به عنوان مثالSingle
،Observable
،Completable
) را بهState
آهنگسازی تبدیل می کنند.وابستگی زیر در پرونده
build.gradle
مورد نیاز است:
کاتلین
dependencies {
...
implementation("androidx.compose.runtime:runtime-rxjava3:1.8.1")
}
شیار
dependencies {
...
implementation "androidx.compose.runtime:runtime-rxjava3:1.8.1"
}
در مقابل بدون تابعیت
یک ترکیب که از remember
برای ذخیره یک شی استفاده می کند ، وضعیت داخلی ایجاد می کند و باعث می شود که این ترکیب مطبوع باشد . HelloContent
نمونه ای از یک ترکیب مطبوع است زیرا وضعیت name
خود را در داخل کشور نگه می دارد و اصلاح می کند. این می تواند در شرایطی مفید باشد که یک تماس گیرنده نیازی به کنترل دولت ندارد و می تواند بدون نیاز به مدیریت خود دولت از آن استفاده کند. با این حال ، ترکیبات با وضعیت داخلی تمایل به استفاده مجدد و آزمایش سخت تر دارند.
یک ترکیب بدون تابعیت یک ترکیب است که هیچ وضعیتی را در خود جای نمی دهد. یک راه آسان برای دستیابی به بی تابعیت استفاده از بالا بردن دولت است.
از آنجا که ساختارهای قابل استفاده مجدد را توسعه می دهید ، اغلب می خواهید یک نسخه دولتی و بدون تابعیت از همان آهنگسازی را در معرض دید قرار دهید. نسخه مطبوع برای تماس گیرنده هایی که به دولت اهمیتی نمی دهند مناسب است و نسخه بدون تابعیت برای تماس گیرنده هایی که نیاز به کنترل یا بلند کردن دولت دارند ضروری است.
دولت بالایی
بلند کردن دولت در آهنگسازی الگویی برای انتقال حالت به تماس گیرنده یک آهنگساز برای ایجاد یک کمبود تابعیت است. الگوی کلی برای بلند کردن حالت در آهنگسازی JetPack ، جایگزینی متغیر حالت با دو پارامتر است:
-
value: T
: مقدار فعلی برای نمایش -
onValueChange: (T) -> Unit
: رویدادی که ارزش تغییر را دارد ، جایی کهT
مقدار جدید پیشنهادی است
با این حال ، شما محدود به onValueChange
نیستید. اگر رویدادهای خاص تر برای ترکیب مناسب هستند ، باید آنها را با استفاده از لامبدا تعریف کنید.
حالت که از این طریق بلند شده است ، برخی از خواص مهم دارد:
- منبع واحد حقیقت: با حرکت به جای کپی کردن آن ، ما اطمینان حاصل می کنیم که تنها یک منبع حقیقت وجود دارد. این به جلوگیری از اشکالات کمک می کند.
- محاصره شده: فقط آهنگسازان مطرح می توانند وضعیت خود را اصلاح کنند. کاملاً داخلی است.
- اشتراکی: حالت بلند شده را می توان با چندین ترکیب مشترک به اشتراک گذاشت. اگر می خواستید
name
در یک ترکیب متفاوت بخوانید ، بالا بردن به شما امکان می دهد این کار را انجام دهید. - رهگیری: تماس گیرندگان به ترکیبات بدون تابعیت می توانند تصمیم بگیرند که قبل از تغییر حالت ، وقایع را نادیده بگیرند یا اصلاح کنند.
- جداشده: وضعیت ترکیبات بدون تابعیت ممکن است در هر جایی ذخیره شود. به عنوان مثال ، اکنون می توان
name
به یکViewModel
منتقل کرد.
در مورد مثال ، شما name
و onValueChange
را از HelloContent
استخراج می کنید و آنها را از درخت به سمت یک ترکیب HelloScreen
که HelloContent
می نامد ، بالا می برید.
@Composable fun HelloScreen() { var name by rememberSaveable { mutableStateOf("") } HelloContent(name = name, onNameChange = { name = it }) } @Composable fun HelloContent(name: String, onNameChange: (String) -> Unit) { Column(modifier = Modifier.padding(16.dp)) { Text( text = "Hello, $name", modifier = Modifier.padding(bottom = 8.dp), style = MaterialTheme.typography.bodyMedium ) OutlinedTextField(value = name, onValueChange = onNameChange, label = { Text("Name") }) } }
با بالا بردن دولت از HelloContent
، استدلال در مورد آهنگسازی ، استفاده مجدد از آن در موقعیت های مختلف و آزمایش ساده تر است. HelloContent
از نحوه ذخیره وضعیت آن جدا می شود. جداشدن به این معنی است که اگر HelloScreen
تغییر داده یا جایگزین کنید ، لازم نیست نحوه اجرای HelloContent
را تغییر دهید.

الگویی که در آن دولت پایین می رود ، و وقایع بالا می رود ، جریان داده های یک طرفه نامیده می شود. در این حالت ، دولت از HelloScreen
به HelloContent
پایین می آید و رویدادها از HelloContent
به HelloScreen
می روند. با پیروی از جریان داده های یک طرفه ، می توانید آهنگسازهایی را که در UI از قسمت های برنامه خود استفاده می کنند ، جدا کنید.
برای کسب اطلاعات بیشتر به صفحه حالت بالابر مراجعه کنید.
بازگرداندن حالت در آهنگسازی
API rememberSaveable
که به طور مشابه به remember
، زیرا این حالت را در بین بازپرداخت ها حفظ می کند ، و همچنین در طول فعالیت یا تفریح فرآیند با استفاده از مکانیسم حالت ذخیره شده ذخیره شده. به عنوان مثال ، این اتفاق می افتد ، هنگامی که صفحه چرخانده می شود.
راه های ذخیره ایالت
تمام انواع داده هایی که به Bundle
اضافه می شوند به طور خودکار ذخیره می شوند. اگر می خواهید چیزی را ذخیره کنید که نمی تواند به Bundle
اضافه شود ، گزینه های مختلفی وجود دارد.
بسته بندی کردن
ساده ترین راه حل اضافه کردن حاشیه نویسی @Parcelize
به شی است. شیء قابل بسته شدن است و می تواند همراه باشد. به عنوان مثال ، این کد نوع داده های قابل حمل City
را ایجاد می کند و آن را در ایالت ذخیره می کند.
@Parcelize data class City(val name: String, val country: String) : Parcelable @Composable fun CityScreen() { var selectedCity = rememberSaveable { mutableStateOf(City("Madrid", "Spain")) } }
ماشین ساز
اگر به دلایلی @Parcelize
مناسب نباشد ، می توانید از mapSaver
برای تعریف قانون خود برای تبدیل یک شی به مجموعه ای از مقادیر استفاده کنید که سیستم می تواند در Bundle
ذخیره کند.
data class City(val name: String, val country: String) val CitySaver = run { val nameKey = "Name" val countryKey = "Country" mapSaver( save = { mapOf(nameKey to it.name, countryKey to it.country) }, restore = { City(it[nameKey] as String, it[countryKey] as String) } ) } @Composable fun CityScreen() { var selectedCity = rememberSaveable(stateSaver = CitySaver) { mutableStateOf(City("Madrid", "Spain")) } }
فهرست ساز
برای جلوگیری از نیاز به تعریف کلیدهای نقشه ، می توانید از listSaver
نیز استفاده کرده و از شاخص های آن به عنوان کلیدها استفاده کنید:
data class City(val name: String, val country: String) val CitySaver = listSaver<City, Any>( save = { listOf(it.name, it.country) }, restore = { City(it[0] as String, it[1] as String) } ) @Composable fun CityScreen() { var selectedCity = rememberSaveable(stateSaver = CitySaver) { mutableStateOf(City("Madrid", "Spain")) } }
دارندگان ایالتی در آهنگسازی
بالابر حالت ساده را می توان در خود توابع ساختگی مدیریت کرد. با این حال ، اگر میزان وضعیت برای پیگیری افزایش ، یا منطق انجام در کارکردهای سازنده بوجود می آید ، این یک عمل خوب است که منطق و مسئولیت های دولت را به سایر کلاس ها واگذار کنید: دارندگان دولت .
برای کسب اطلاعات بیشتر ، به بالا بردن دولت در مستندات آهنگسازی یا به طور کلی ، دارندگان ایالتی و صفحه ایالتی UI در راهنمای معماری مراجعه کنید.
محاسبات هنگام تغییر کلیدها محاسبات را به خاطر بسپارید
API remember
که اغلب همراه با MutableState
استفاده می شود:
var name by remember { mutableStateOf("") }
در اینجا ، با استفاده از عملکرد remember
، مقدار MutableState
باعث زنده ماندن مجدد می شود.
به طور کلی ، remember
یک پارامتر لامبدا calculation
می کند. هنگامی که remember
اولین بار اجرا می شود ، calculation
لامبدا را فراخوانی می کند و نتیجه خود را ذخیره می کند. در حین بازپرداخت ، remember
مقداری را که آخرین بار در آن ذخیره شده بود باز می گرداند.
به غیر از حالت ذخیره ، می توانید remember
برای ذخیره هر شی یا نتیجه عملیاتی در ترکیب استفاده کنید که برای اولیه سازی یا محاسبه گران است. ممکن است شما بخواهید این محاسبه را در هر بازپرداخت تکرار کنید. به عنوان مثال ، ایجاد این شیء ShaderBrush
است که یک عملیات گران قیمت است:
val brush = remember { ShaderBrush( BitmapShader( ImageBitmap.imageResource(res, avatarRes).asAndroidBitmap(), Shader.TileMode.REPEAT, Shader.TileMode.REPEAT ) ) }
remember
مقدار را تا زمانی که ترکیب را ترک کند ، ذخیره می کند. با این حال ، راهی برای باطل کردن مقدار ذخیره شده وجود دارد. API remember
همچنین یک پارامتر key
یا keys
را می گیرد. اگر هرکدام از این کلیدها تغییر می کنند ، دفعه بعد که عملکرد دوباره انجام می شود ، remember
که حافظه نهان را باطل می کند و بلوک لامبدا محاسبه را دوباره اجرا می کند . این مکانیسم به شما امکان کنترل عمر یک شی را در ترکیب می دهد. محاسبه تا زمانی که ورودی ها تغییر کنند ، معتبر است ، به جای اینکه مقدار به یاد داشته باشید که ترکیب را ترک می کند.
مثالهای زیر نشان می دهد که چگونه این مکانیسم کار می کند.
در این قطعه ، یک ShaderBrush
ایجاد شده و به عنوان رنگ پس زمینه یک Box
قابل استفاده استفاده می شود. همانطور که در ابتدا توضیح داده شد ، remember
که نمونه ShaderBrush
را به خاطر اینکه بازآفرینی آن گران است. remember
avatarRes
به عنوان پارامتر key1
، که تصویر پس زمینه انتخاب شده است ، می گیرد. اگر avatarRes
تغییر کند ، برس با تصویر جدید توصیه می شود و دوباره به Box
استفاده می شود. این ممکن است زمانی رخ دهد که کاربر تصویر دیگری را انتخاب کند تا پس زمینه یک انتخاب کننده باشد.
@Composable private fun BackgroundBanner( @DrawableRes avatarRes: Int, modifier: Modifier = Modifier, res: Resources = LocalContext.current.resources ) { val brush = remember(key1 = avatarRes) { ShaderBrush( BitmapShader( ImageBitmap.imageResource(res, avatarRes).asAndroidBitmap(), Shader.TileMode.REPEAT, Shader.TileMode.REPEAT ) ) } Box( modifier = modifier.background(brush) ) { /* ... */ } }
در قطعه بعدی ، ایالت به یک کلاس دارنده ایالتی ساده MyAppState
بلند می شود. این یک تابع rememberMyAppState
برای شروع نمونه ای از کلاس با استفاده از remember
در معرض دید قرار می دهد. قرار گرفتن در معرض چنین توابع برای ایجاد نمونه ای که زنده مانده است ، یک الگوی مشترک در آهنگسازی است. تابع rememberMyAppState
windowSizeClass
دریافت می کند ، که به عنوان پارامتر key
برای remember
عمل می کند. اگر این پارامتر تغییر کند ، برنامه باید کلاس نگهدارنده حالت ساده را با جدیدترین مقدار بازآفرینی کند. این ممکن است رخ دهد اگر مثلاً کاربر دستگاه را بچرخاند.
@Composable private fun rememberMyAppState( windowSizeClass: WindowSizeClass ): MyAppState { return remember(windowSizeClass) { MyAppState(windowSizeClass) } } @Stable class MyAppState( private val windowSizeClass: WindowSizeClass ) { /* ... */ }
آهنگسازی از اجرای Equals Equals استفاده می کند تا تصمیم بگیرد که آیا یک کلید تغییر کرده و مقدار ذخیره شده را باطل می کند.
حالت را با کلیدهای فراتر از بازپرداخت ذخیره کنید
API rememberSaveable
remember
یک بسته بندی در اطراف است که می تواند داده ها را در یک Bundle
ذخیره کند. این API به دولت اجازه می دهد تا نه تنها از بازپرداخت ، بلکه فعالیت های تفریحی فعالیت و مرگ فرآیند سیستم را نیز زنده بماند. rememberSaveable
پارامترهای input
را برای همان هدفی که remember
keys
دریافت می کند ، دریافت می کند. هنگامی که هر یک از ورودی ها تغییر می کنند ، حافظه پنهان باطل می شود . دفعه بعد که عملکرد دوباره انجام می شود ، rememberSaveable
که قابل استفاده مجدد بلوک لامبدا محاسبه می شود.
در مثال زیر ، فروشگاه های قابل حمل userTypedQuery
rememberSaveable
تا زمانی که typedQuery
تغییر کند:
var userTypedQuery by rememberSaveable(typedQuery, stateSaver = TextFieldValue.Saver) { mutableStateOf( TextFieldValue(text = typedQuery, selection = TextRange(typedQuery.length)) ) }
بیشتر بدانید
برای کسب اطلاعات بیشتر در مورد Constate State و JetPack ، با منابع اضافی زیر مشورت کنید.
نمونه ها
Codelabs
ویدیوها
وبلاگ ها
{٪ کلمه ٪}برای شما توصیه می شود
- توجه: هنگام خاموش بودن جاوا اسکریپت ، متن پیوند نمایش داده می شود
- معماری UI آهنگسازی شما
- وضعیت UI را در آهنگسازی ذخیره کنید
- عوارض جانبی در آهنگسازی
حالت در یک برنامه هر ارزشی است که می تواند با گذشت زمان تغییر کند. این یک تعریف بسیار گسترده است و همه چیز را از یک پایگاه داده اتاق گرفته تا یک متغیر در یک کلاس در بر می گیرد.
همه برنامه های Android وضعیت را به کاربر نشان می دهند. چند نمونه از حالت در برنامه های Android:
- اسنکبر که نشان می دهد چه زمانی نمی توان اتصال شبکه برقرار کرد.
- یک پست وبلاگ و نظرات مرتبط.
- انیمیشن های ریپل روی دکمه هایی که وقتی کاربر روی آنها کلیک می کند بازی می کنند.
- برچسب هایی که کاربر می تواند در بالای یک تصویر ترسیم کند.
JetPack Compose به شما کمک می کند تا در مورد مکان و نحوه ذخیره و استفاده از حالت در یک برنامه Android صریح باشید. این راهنما به ارتباط بین حالت و ترکیبات و API هایی که Jetpack Compose ارائه می دهد برای کار راحت تر با حالت ارائه می دهد.
حالت و ترکیب
آهنگسازی اعلامی است و به همین ترتیب تنها راه به روزرسانی آن با فراخوانی همان ترکیب با استدلال های جدید است. این استدلال ها بازنمایی از دولت UI است. هر زمان که یک حالت به روز شود ، بازپرداخت صورت می گیرد. در نتیجه ، مواردی مانند TextField
به طور خودکار مانند آنچه در نماهای مبتنی بر XML انجام می شود به روز نمی شوند. یک ترکیب باید صریحاً به حالت جدید گفته شود تا بتواند بر این اساس به روز شود.
@Composable private fun HelloContent() { Column(modifier = Modifier.padding(16.dp)) { Text( text = "Hello!", modifier = Modifier.padding(bottom = 8.dp), style = MaterialTheme.typography.bodyMedium ) OutlinedTextField( value = "", onValueChange = { }, label = { Text("Name") } ) } }
اگر این کار را اجرا کنید و سعی کنید متن را وارد کنید ، می بینید که هیچ اتفاقی نمی افتد. به این دلیل است که TextField
خود را به روز نمی کند - وقتی پارامتر value
آن تغییر می کند ، به روز می شود. این به دلیل نحوه کار ترکیب و بازپرداخت در آهنگسازی است.
برای کسب اطلاعات بیشتر در مورد ترکیب اولیه و تجدید نظر ، به تفکر در آهنگسازی مراجعه کنید.
حالت در ترکیبات
توابع کامپوزیت می توانند از API remember
تا یک شی را در حافظه ذخیره کنید. مقداری محاسبه شده توسط remember
در طول ترکیب اولیه در ترکیب ذخیره می شود و مقدار ذخیره شده در طول بازپرداخت بازگردانده می شود. remember
می توانید برای ذخیره هر دو اشیاء قابل تغییر و تغییر ناپذیر استفاده کنید.
mutableStateOf
یک MutableState<T>
ایجاد می کند ، که یک نوع قابل مشاهده است که با زمان اجرای آهنگسازی یکپارچه شده است.
interface MutableState<T> : State<T> {
override var value: T
}
هرگونه تغییر در برنامه های value
، بازآفرینی از هر کارکرد ترکیب را که value
می خوانند ، می کند.
سه روش برای اعلام یک شیء MutableState
در یک ترکیب وجود دارد:
-
val mutableState = remember { mutableStateOf(default) }
-
var value by remember { mutableStateOf(default) }
-
val (value, setValue) = remember { mutableStateOf(default) }
این اعلامیه ها معادل هستند و به عنوان قند نحوی برای استفاده های مختلف دولت ارائه می شوند. شما باید یکی از مواردی را انتخاب کنید که ساده ترین کد خواندن را در آهنگسازی که می نویسید تولید می کند.
نحو by
نماینده به واردات زیر نیاز دارد:
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
شما می توانید از مقدار به یاد داشته باشید به عنوان یک پارامتر برای سایر آهنگسازان یا حتی به عنوان منطق در بیانیه ها برای تغییر کدام یک از ترکیبات نمایش داده می شود. به عنوان مثال ، اگر نمی خواهید در صورت خالی بودن نام ، تبریک را نمایش دهید ، از حالت در بیانیه if
استفاده کنید:
@Composable fun HelloContent() { Column(modifier = Modifier.padding(16.dp)) { var name by remember { mutableStateOf("") } if (name.isNotEmpty()) { Text( text = "Hello, $name!", modifier = Modifier.padding(bottom = 8.dp), style = MaterialTheme.typography.bodyMedium ) } OutlinedTextField( value = name, onValueChange = { name = it }, label = { Text("Name") } ) } }
در حالی که remember
به شما کمک می کند تا حالت را در بازپرداخت ها حفظ کنید ، دولت در سراسر تغییرات پیکربندی حفظ نمی شود. برای این کار ، شما باید از rememberSaveable
استفاده کنید. rememberSaveable
به طور خودکار هر مقداری را که می تواند در یک Bundle
ذخیره شود ، ذخیره می کند. برای مقادیر دیگر ، می توانید در یک شیء محافظ سفارشی عبور کنید.
سایر انواع پشتیبانی شده دولت
آهنگسازی نیازی به استفاده از MutableState<T>
برای نگه داشتن حالت ندارد. از انواع دیگر قابل مشاهده پشتیبانی می کند. قبل از خواندن نوع قابل مشاهده دیگری در آهنگسازی ، باید آن را به State<T>
تبدیل کنید تا در صورت تغییر حالت ، آهنگسازان بتوانند به طور خودکار دوباره درخواست کنند.
کشتی ها را با توابع برای ایجاد State<T>
از انواع قابل مشاهده متداول که در برنامه های اندرویدی استفاده می شود ، تهیه کنید. قبل از استفاده از این ادغام ها ، مصنوعات (های) مناسب را مطابق شکل زیر اضافه کنید:
Flow
:collectAsStateWithLifecycle()
collectAsStateWithLifecycle()
مقادیر را از یکFlow
به صورت آگاه از چرخه عمر جمع می کند و به برنامه شما اجازه می دهد تا منابع برنامه را حفظ کند. این نشان دهنده آخرین مقدار ساطع شده ازState
آهنگسازی است. از این API به عنوان روش توصیه شده برای جمع آوری جریان در برنامه های Android استفاده کنید.وابستگی زیر در پرونده
build.gradle
مورد نیاز است (باید 2.6.0-beta01 یا جدیدتر باشد):
کاتلین
dependencies {
...
implementation("androidx.lifecycle:lifecycle-runtime-compose:2.8.7")
}
شیار
dependencies {
...
implementation "androidx.lifecycle:lifecycle-runtime-compose:2.8.7"
}
collectAsState
شبیه بهcollectAsStateWithLifecycle
است ، زیرا مقادیر را از یکFlow
نیز جمع می کند و آن را بهState
آهنگسازی تبدیل می کند.به جای
collectAsStateWithLifecycle
، که فقط اندرویدی است ، ازcollectAsState
برای کد پلتفرم-آگنوستیک استفاده کنید.وابستگی های اضافی برای
collectAsState
لازم نیست ، زیرا درcompose-runtime
در دسترس است.observeAsState()
مشاهده اینLiveData
شروع می کند و ارزش های آن را از طریقState
نشان می دهد.وابستگی زیر در پرونده
build.gradle
مورد نیاز است:
کاتلین
dependencies {
...
implementation("androidx.compose.runtime:runtime-livedata:1.8.1")
}
شیار
dependencies {
...
implementation "androidx.compose.runtime:runtime-livedata:1.8.1"
}
subscribeAsState()
توابع پسوند هستند که جریانهای واکنشی rxjava2 (به عنوان مثالSingle
،Observable
،Completable
) را بهState
آهنگسازی تبدیل می کنند.وابستگی زیر در پرونده
build.gradle
مورد نیاز است:
کاتلین
dependencies {
...
implementation("androidx.compose.runtime:runtime-rxjava2:1.8.1")
}
شیار
dependencies {
...
implementation "androidx.compose.runtime:runtime-rxjava2:1.8.1"
}
subscribeAsState()
توابع پسوند هستند که جریانهای واکنشی Rxjava3 (به عنوان مثالSingle
،Observable
،Completable
) را بهState
آهنگسازی تبدیل می کنند.وابستگی زیر در پرونده
build.gradle
مورد نیاز است:
کاتلین
dependencies {
...
implementation("androidx.compose.runtime:runtime-rxjava3:1.8.1")
}
شیار
dependencies {
...
implementation "androidx.compose.runtime:runtime-rxjava3:1.8.1"
}
در مقابل بدون تابعیت
یک ترکیب که از remember
برای ذخیره یک شی استفاده می کند ، وضعیت داخلی ایجاد می کند و باعث می شود که این ترکیب مطبوع باشد . HelloContent
نمونه ای از یک ترکیب مطبوع است زیرا وضعیت name
خود را در داخل کشور نگه می دارد و اصلاح می کند. این می تواند در شرایطی مفید باشد که یک تماس گیرنده نیازی به کنترل دولت ندارد و می تواند بدون نیاز به مدیریت خود دولت از آن استفاده کند. با این حال ، ترکیبات با وضعیت داخلی تمایل به استفاده مجدد و آزمایش سخت تر دارند.
یک ترکیب بدون تابعیت یک ترکیب است که هیچ وضعیتی را در خود جای نمی دهد. یک راه آسان برای دستیابی به بی تابعیت استفاده از بالا بردن دولت است.
از آنجا که ساختارهای قابل استفاده مجدد را توسعه می دهید ، اغلب می خواهید یک نسخه دولتی و بدون تابعیت از همان آهنگسازی را در معرض دید قرار دهید. نسخه مطبوع برای تماس گیرنده هایی که به دولت اهمیتی نمی دهند مناسب است و نسخه بدون تابعیت برای تماس گیرنده هایی که نیاز به کنترل یا بلند کردن دولت دارند ضروری است.
دولت بالایی
بلند کردن دولت در آهنگسازی الگویی برای انتقال حالت به تماس گیرنده یک آهنگساز برای ایجاد یک کمبود تابعیت است. الگوی کلی برای بلند کردن حالت در آهنگسازی JetPack ، جایگزینی متغیر حالت با دو پارامتر است:
-
value: T
: مقدار فعلی برای نمایش -
onValueChange: (T) -> Unit
: رویدادی که ارزش تغییر را دارد ، جایی کهT
مقدار جدید پیشنهادی است
با این حال ، شما محدود به onValueChange
نیستید. اگر رویدادهای خاص تر برای ترکیب مناسب هستند ، باید آنها را با استفاده از لامبدا تعریف کنید.
حالت که از این طریق بلند شده است ، برخی از خواص مهم دارد:
- منبع واحد حقیقت: با حرکت به جای کپی کردن آن ، ما اطمینان حاصل می کنیم که تنها یک منبع حقیقت وجود دارد. این به جلوگیری از اشکالات کمک می کند.
- محاصره شده: فقط آهنگسازان مطرح می توانند وضعیت خود را اصلاح کنند. کاملاً داخلی است.
- اشتراکی: حالت بلند شده را می توان با چندین ترکیب مشترک به اشتراک گذاشت. اگر می خواستید
name
در یک ترکیب متفاوت بخوانید ، بالا بردن به شما امکان می دهد این کار را انجام دهید. - رهگیری: تماس گیرندگان به ترکیبات بدون تابعیت می توانند تصمیم بگیرند که قبل از تغییر حالت ، وقایع را نادیده بگیرند یا اصلاح کنند.
- جداشده: وضعیت ترکیبات بدون تابعیت ممکن است در هر جایی ذخیره شود. به عنوان مثال ، اکنون می توان
name
به یکViewModel
منتقل کرد.
در مورد مثال ، شما name
و onValueChange
را از HelloContent
استخراج می کنید و آنها را از درخت به سمت یک ترکیب HelloScreen
که HelloContent
می نامد ، بالا می برید.
@Composable fun HelloScreen() { var name by rememberSaveable { mutableStateOf("") } HelloContent(name = name, onNameChange = { name = it }) } @Composable fun HelloContent(name: String, onNameChange: (String) -> Unit) { Column(modifier = Modifier.padding(16.dp)) { Text( text = "Hello, $name", modifier = Modifier.padding(bottom = 8.dp), style = MaterialTheme.typography.bodyMedium ) OutlinedTextField(value = name, onValueChange = onNameChange, label = { Text("Name") }) } }
با بالا بردن دولت از HelloContent
، استدلال در مورد آهنگسازی ، استفاده مجدد از آن در موقعیت های مختلف و آزمایش ساده تر است. HelloContent
از نحوه ذخیره وضعیت آن جدا می شود. جداشدن به این معنی است که اگر HelloScreen
تغییر داده یا جایگزین کنید ، لازم نیست نحوه اجرای HelloContent
را تغییر دهید.

الگویی که در آن دولت پایین می رود ، و وقایع بالا می رود ، جریان داده های یک طرفه نامیده می شود. در این حالت ، دولت از HelloScreen
به HelloContent
پایین می آید و رویدادها از HelloContent
به HelloScreen
می روند. با پیروی از جریان داده های یک طرفه ، می توانید آهنگسازهایی را که در UI از قسمت های برنامه خود استفاده می کنند ، جدا کنید.
برای کسب اطلاعات بیشتر به صفحه حالت بالابر مراجعه کنید.
بازگرداندن حالت در آهنگسازی
API rememberSaveable
که به طور مشابه به remember
، زیرا این حالت را در بین بازپرداخت ها حفظ می کند ، و همچنین در طول فعالیت یا تفریح فرآیند با استفاده از مکانیسم حالت ذخیره شده ذخیره شده. به عنوان مثال ، این اتفاق می افتد ، هنگامی که صفحه چرخانده می شود.
راه های ذخیره ایالت
تمام انواع داده هایی که به Bundle
اضافه می شوند به طور خودکار ذخیره می شوند. اگر می خواهید چیزی را ذخیره کنید که نمی تواند به Bundle
اضافه شود ، گزینه های مختلفی وجود دارد.
بسته بندی کردن
ساده ترین راه حل اضافه کردن حاشیه نویسی @Parcelize
به شی است. شیء قابل بسته شدن است و می تواند همراه باشد. به عنوان مثال ، این کد نوع داده های قابل حمل City
را ایجاد می کند و آن را در ایالت ذخیره می کند.
@Parcelize data class City(val name: String, val country: String) : Parcelable @Composable fun CityScreen() { var selectedCity = rememberSaveable { mutableStateOf(City("Madrid", "Spain")) } }
ماشین ساز
اگر به دلایلی @Parcelize
مناسب نباشد ، می توانید از mapSaver
برای تعریف قانون خود برای تبدیل یک شی به مجموعه ای از مقادیر استفاده کنید که سیستم می تواند در Bundle
ذخیره کند.
data class City(val name: String, val country: String) val CitySaver = run { val nameKey = "Name" val countryKey = "Country" mapSaver( save = { mapOf(nameKey to it.name, countryKey to it.country) }, restore = { City(it[nameKey] as String, it[countryKey] as String) } ) } @Composable fun CityScreen() { var selectedCity = rememberSaveable(stateSaver = CitySaver) { mutableStateOf(City("Madrid", "Spain")) } }
فهرست ساز
برای جلوگیری از نیاز به تعریف کلیدهای نقشه ، می توانید از listSaver
نیز استفاده کرده و از شاخص های آن به عنوان کلیدها استفاده کنید:
data class City(val name: String, val country: String) val CitySaver = listSaver<City, Any>( save = { listOf(it.name, it.country) }, restore = { City(it[0] as String, it[1] as String) } ) @Composable fun CityScreen() { var selectedCity = rememberSaveable(stateSaver = CitySaver) { mutableStateOf(City("Madrid", "Spain")) } }
دارندگان ایالتی در آهنگسازی
بالابر حالت ساده را می توان در خود توابع ساختگی مدیریت کرد. با این حال ، اگر میزان وضعیت برای پیگیری افزایش ، یا منطق انجام در کارکردهای سازنده بوجود می آید ، این یک عمل خوب است که منطق و مسئولیت های دولت را به سایر کلاس ها واگذار کنید: دارندگان دولت .
برای کسب اطلاعات بیشتر ، به بالا بردن دولت در مستندات آهنگسازی یا به طور کلی ، دارندگان ایالتی و صفحه ایالتی UI در راهنمای معماری مراجعه کنید.
محاسبات هنگام تغییر کلیدها محاسبات را به خاطر بسپارید
API remember
که اغلب همراه با MutableState
استفاده می شود:
var name by remember { mutableStateOf("") }
در اینجا ، با استفاده از عملکرد remember
، مقدار MutableState
باعث زنده ماندن مجدد می شود.
به طور کلی ، remember
یک پارامتر لامبدا calculation
می کند. هنگامی که remember
اولین بار اجرا می شود ، calculation
لامبدا را فراخوانی می کند و نتیجه خود را ذخیره می کند. در حین بازپرداخت ، remember
مقداری را که آخرین بار در آن ذخیره شده بود باز می گرداند.
به غیر از حالت ذخیره ، می توانید remember
برای ذخیره هر شی یا نتیجه عملیاتی در ترکیب استفاده کنید که برای اولیه سازی یا محاسبه گران است. ممکن است شما بخواهید این محاسبه را در هر بازپرداخت تکرار کنید. به عنوان مثال ، ایجاد این شیء ShaderBrush
است که یک عملیات گران قیمت است:
val brush = remember { ShaderBrush( BitmapShader( ImageBitmap.imageResource(res, avatarRes).asAndroidBitmap(), Shader.TileMode.REPEAT, Shader.TileMode.REPEAT ) ) }
remember
مقدار را تا زمانی که ترکیب را ترک کند ، ذخیره می کند. با این حال ، راهی برای باطل کردن مقدار ذخیره شده وجود دارد. API remember
همچنین یک پارامتر key
یا keys
را می گیرد. اگر هرکدام از این کلیدها تغییر می کنند ، دفعه بعد که عملکرد دوباره انجام می شود ، remember
که حافظه نهان را باطل می کند و بلوک لامبدا محاسبه را دوباره اجرا می کند . این مکانیسم به شما امکان کنترل عمر یک شی را در ترکیب می دهد. محاسبه تا زمانی که ورودی ها تغییر کنند ، معتبر است ، به جای اینکه مقدار به یاد داشته باشید که ترکیب را ترک می کند.
مثالهای زیر نشان می دهد که چگونه این مکانیسم کار می کند.
در این قطعه ، یک ShaderBrush
ایجاد شده و به عنوان رنگ پس زمینه یک Box
قابل استفاده استفاده می شود. همانطور که در ابتدا توضیح داده شد ، remember
که نمونه ShaderBrush
را به خاطر اینکه بازآفرینی آن گران است. remember
avatarRes
به عنوان پارامتر key1
، که تصویر پس زمینه انتخاب شده است ، می گیرد. اگر avatarRes
تغییر کند ، برس با تصویر جدید توصیه می شود و دوباره به Box
استفاده می شود. این ممکن است زمانی رخ دهد که کاربر تصویر دیگری را انتخاب کند تا پس زمینه یک انتخاب کننده باشد.
@Composable private fun BackgroundBanner( @DrawableRes avatarRes: Int, modifier: Modifier = Modifier, res: Resources = LocalContext.current.resources ) { val brush = remember(key1 = avatarRes) { ShaderBrush( BitmapShader( ImageBitmap.imageResource(res, avatarRes).asAndroidBitmap(), Shader.TileMode.REPEAT, Shader.TileMode.REPEAT ) ) } Box( modifier = modifier.background(brush) ) { /* ... */ } }
در قطعه بعدی ، ایالت به یک کلاس دارنده ایالتی ساده MyAppState
بلند می شود. این یک تابع rememberMyAppState
برای شروع نمونه ای از کلاس با استفاده از remember
در معرض دید قرار می دهد. قرار گرفتن در معرض چنین توابع برای ایجاد نمونه ای که زنده مانده است ، یک الگوی مشترک در آهنگسازی است. تابع rememberMyAppState
windowSizeClass
دریافت می کند ، که به عنوان پارامتر key
برای remember
عمل می کند. If this parameter changes, the app needs to recreate the plain state holder class with the latest value. This may occur if, for example, the user rotates the device.
@Composable private fun rememberMyAppState( windowSizeClass: WindowSizeClass ): MyAppState { return remember(windowSizeClass) { MyAppState(windowSizeClass) } } @Stable class MyAppState( private val windowSizeClass: WindowSizeClass ) { /* ... */ }
Compose uses the class's equals implementation to decide if a key has changed and invalidate the stored value.
Store state with keys beyond recomposition
The rememberSaveable
API is a wrapper around remember
that can store data in a Bundle
. This API allows state to survive not only recomposition, but also activity recreation and system-initiated process death. rememberSaveable
receives input
parameters for the same purpose that remember
receives keys
. The cache is invalidated when any of the inputs change . The next time the function recomposes, rememberSaveable
re-executes the calculation lambda block.
In the following example, rememberSaveable
stores userTypedQuery
until typedQuery
changes:
var userTypedQuery by rememberSaveable(typedQuery, stateSaver = TextFieldValue.Saver) { mutableStateOf( TextFieldValue(text = typedQuery, selection = TextRange(typedQuery.length)) ) }
بیشتر بدانید
To learn more about state and Jetpack Compose, consult the following additional resources.
نمونه ها
Codelabs
ویدیوها
وبلاگ ها
{% verbatim %}برای شما توصیه می شود
- Note: link text is displayed when JavaScript is off
- Architecting your Compose UI
- Save UI state in Compose
- Side-effects in Compose