remember — تابعی در Jetpack Compose است که به شما امکان میدهد مقدار را بین بازترکیبها ذخیره کنید و از بازنشانی وضعیت در هر راهاندازی مجدد تابع Composable جلوگیری کنید. بدون remember، تمام متغیرهای اعلام شده در داخل تابع در هر بهروزرسانی UI بازنشانی میشدند و وضعیت را ناپایدار و بیفایده میکردند. به گفته Google Android Developers, 2026، استفاده صحیح از remember اساس مدیریت صحیح وضعیت در UI اعلانی است.
نکات اصلی
remember — یک تابع داخلی Jetpack Compose از بسته androidx.compose.runtime است که شیئی ایجاد میکند که مقدار خود را بین فراخوانیهای متوالی تابع Composable حفظ میکند. از نظر فنی، remember با slotها کار میکند — سلولهای حافظه ویژهای که برای هر موقعیت فراخوانی تابع در درخت UI اختصاص داده شدهاند. تا زمانی که تابع در ترکیب باقی بماند (با شرط if حذف نشده باشد)، remember در هر بازترکیب مقدار ذخیرهشده را برمیگرداند.
نحو remember ساده است: در داخل آکولادها، بلوک محاسبه مقدار اولیه مشخص میشود. بلوک فقط یک بار — در اولین ترکیب تابع — اجرا میشود. تمام بازترکیبهای بعدی مقدار ذخیرهشده را برمیگردانند، بدون اینکه بلوک دوباره فراخوانی شود. با این حال، اگر یک کلید (پارامتر key) مشخص شده باشد، بلوک با تغییر کلید دوباره اجرا میشود که امکان محاسبه مجدد مقدار را بر اساس دادههای ورودی فراهم میکند.
remember جادوی Kotlin نیست — این یک تابع ساده با پارامتر key و لامبدا محاسبه است. پیادهسازی داخلی آن از Composer برای خواندن و نوشتن در slotها استفاده میکند. کامپایلر Kotlin با مشاهده فراخوانی remember، کدی تولید میکند که به CompositionContext فعلی دسترسی پیدا کرده و slotها را مدیریت میکند. این بدان معناست که remember فقط در داخل تابع Composable یا تابع دیگری در زمینه ترکیب قابل فراخوانی است.
در Jetpack Compose سه نوع اصلی remember وجود دارد که هر کدام هدف خاص خود را دارند. remember پایه مقدار را فقط در حافظه فرآیند فعلی ذخیره میکند — هنگام چرخش صفحه (config change)، Compose Composition را دوباره ایجاد میکند و تمام مقادیر remember بازنشانی میشوند. برای ذخیره دادهها در تغییرات پیکربندی و توقف فرآیند از rememberSaveable استفاده میشود.
rememberSaveable مقدار را از طریق مکانیزم SavedStateHandle یا Parcelable در Bundle سریالسازی میکند. این امکان زنده ماندن در چرخش صفحه، فراخوانی «فعالیتها را حفظ نکن» و حتی کوچکسازی موقت برنامه را فراهم میکند. با این حال، rememberSaveable محدودیتهایی بر نوع دادههای ذخیرهشده اعمال میکند: آنها باید primitives، Parcelable، Serializable باشند یا از مبدل Saver پشتیبانی کنند.
derivedStateOf — یک مکانیزم ذخیرهسازی نیست، بلکه بهینهسازی است. Stateای ایجاد میکند که مقدار آن بر اساس سایر اشیاء State محاسبه میشود. derivedStateOf به تغییرات حالتهای منبع واکنش نشان میدهد، اما مقدار را فقط در صورت وجود مشترکین محاسبه میکند. اگر بازترکیب فعلی derivedStateOf را نخواند، محاسبه انجام نمیشود که در بهروزرسانیهای مکرر اما غیرضروری در مصرف منابع صرفهجویی میکند.
@Composable
fun RememberVariants() {
// 1. remember پایه: تا خروج از ترکیب باقی میماند
val createdAt = remember { System.currentTimeMillis() }
// 2. rememberSaveable: از چرخش صفحه جان سالم به در میبرد
var username by rememberSaveable { mutableStateOf("") }
// 3. derivedStateOf: فقط در صورت نیاز محاسبه میشود
val isButtonVisible = remember {
derivedStateOf { username.length() > 3 }
}
Text("ایجاد شده: $createdAt")
TextField(value = username, onValueChange = { username = it })
if (isButtonVisible.value) {
Text("دکمه نشان داده خواهد شد")
}
}
انتخاب بین remember و rememberSaveable بستگی به این دارد که ذخیره دادهها در تغییرات پیکربندی چقدر حیاتی است. برای حالتهای موقتی که از دست دادن آنها در چرخش مهم نیست (انیمیشن، موقعیت فعلی اسکرول، حالت فوکوس) — remember معمولی کافی است. برای دادههای حیاتی (متن در فرم، عناصر انتخابشده، چکباکسها) — از rememberSaveable استفاده کنید.
عملکرد rememberSaveable پایینتر از remember معمولی است زیرا نیاز به سریالسازی در Bundle دارد. از rememberSaveable فقط برای دادههایی استفاده کنید که واقعاً باید از بازسازی Activity جان سالم به در ببرند. برای بقیه موارد — remember ساده. استفاده بیش از حد از rememberSaveable منجر به کندی در چرخش صفحه و جابجایی بین برنامهها میشود.
اگر با کلاسهایی کار میکنید که از Parcelable یا Serializable پشتیبانی نمیکنند، از Saver استفاده کنید — مبدلی که تعیین میکند چگونه شیء را ذخیره و بازیابی کند. Saver با یک جفت لامبدا توصیف میشود: save (شیء را به نوع قابل ذخیره تبدیل میکند) و restore (شیء را از دادههای ذخیرهشده بازیابی میکند). Saver استاندارد قبلاً برای mutableStateListOf و mutableStateMapOf پیادهسازی شده است.
| ویژگی | remember | rememberSaveable |
|---|---|---|
| ذخیره در بازترکیب | بله | بله |
| ذخیره در چرخش | خیر | بله |
| ذخیره در توقف فرآیند | خیر | بله |
| الزامات نوع | هر نوع | Parcelable، Serializable، Saver |
| عملکرد | بالا | متوسط |
بیایید یک سناریوی معمولی را در نظر بگیریم — صفحه ویرایش پروفایل، جایی که remember برای چندین هدف استفاده میشود: ذخیره وضعیت فیلدهای فرم، محاسبه مقادیر مشتقشده و کش کردن عملیاتهای پرهزینه محاسباتی.
data class ProfileUiState(
val name: String = "",
val bio: String = "",
val isSaving: Boolean = false
)
@Composable
fun ProfileEditor() {
var state by rememberSaveable { mutableStateOf(ProfileUiState()) }
val isValid = remember {
derivedStateOf { state.name.isNotBlank() && state.bio.length() <= 500 }
}
val bioWarning = remember(state.bio) {
if (state.bio.length() > 400) {
"${500 - state.bio.length} chars left"
} else null
}
Column(modifier = Modifier.padding(16.dp)) {
OutlinedTextField(
value = state.name,
onValueChange = { state = state.copy(name = it) },
label = { Text("نام") }
)
OutlinedTextField(
value = state.bio,
onValueChange = { state = state.copy(bio = it) },
label = { Text("درباره") }
)
bioWarning?.let { Text(it, color = MaterialTheme.colorScheme.error) }
Button(onClick = { /* save */ },
enabled = isValid.value) {
Text("ذخیره")
}
}
}
در مثال، وضعیت از طریق rememberSaveable ذخیره میشود — در چرخش صفحه متن از بین نمیرود. isValid از طریق derivedStateOf محاسبه میشود که از محاسبات اضافی در بازترکیبها جلوگیری میکند. bioWarning از remember با کلید bio استفاده میکند — این یک محاسبه پرهزینه (اختیاری، برای نمایش) است که فقط با تغییر bio دوباره محاسبه میشود، نه در هر بازترکیب.
وضعیتهای مشتقشده (derived state) مقادیری هستند که از سایر اشیاء State محاسبه میشوند. به جای محاسبه آنها در هر بازترکیب و هدر دادن CPU روی نتایج یکسان، remember با derivedStateOf مقدار را فقط هنگام تغییر منابع محاسبه میکند. این به ویژه برای فیلتر کردن، مرتبسازی و تجمیع دادهها مفید است.
remember با کلیدها (remember(key) { calculation }) — مکانیزم بهینهسازی دیگری است. اگر کلید از بازترکیب قبلی تغییر نکرده باشد، بلوک محاسبه اجرا نمیشود و مقدار کششده برگردانده میشود. این برای کش کردن اشیایی که ایجاد آنها پرهزینه است مفید است: قالببندی تاریخها، تجزیه JSON، ایجاد مجموعههای تغییرناپذیر بزرگ.
@Composable
fun SearchResults(allItems: List<Item>, query: String) {
// derivedStateOf: فیلتر فقط زمانی که ورودیها تغییر کنند دوباره محاسبه میشود
val filtered = remember {
derivedStateOf {
allItems.filter { it.title.contains(query, true) }
}
}
// remember با کلید: آمار قالببندیشده فقط با تغییر جستجو دوباره محاسبه میشود
val statsText = remember(query) {
"Results for query \"$query\": ${filtered.value.size}"
}
Text(statsText)
LazyColumn {
items(filtered.value, key = { it.id }) { item ->
Text(item.title)
}
}
}
filtered — یک derivedStateOf است که با تغییر allItems یا query به طور خودکار دوباره محاسبه میشود. statsText از remember(query) استفاده میکند — قالببندی پرهزینه رشته فقط هنگام تغییر عبارت جستجو اجرا میشود. ترکیب derivedStateOf و remember با کلیدها حداکثر عملکرد را ارائه میدهد: وضعیت مشتقشده فقط زمانی که لازم است محاسبه میشود و اشیاء پیچیده تا تغییر کلید کش میشوند.
سوالات متداول
خیر، remember — تابعی از بسته compose.runtime است که به CompositionContext نیاز دارد. این تابع فقط در داخل تابع @Composable یا داخل تابع دیگری که از Composable فراخوانی شده است قابل فراخوانی است. برای ذخیره دادهها خارج از ترکیب از ViewModel استفاده کنید.
بدون کلید، remember بلوک را فقط یک بار — در اولین ترکیب — محاسبه میکند. تمام بازترکیبهای بعدی مقدار ذخیرهشده را برمیگردانند. اگر نیاز به محاسبه مجدد مقدار با تغییر دادهها دارید، حتماً آنها را به عنوان کلید مشخص کنید: remember(data) { compute(data) }.
بازنشانی مستقیم remember وجود ندارد. تنها راه — خارج کردن تابع از ترکیب (مثلاً با پنهان کردن از طریق شرط if) و سپس نشان دادن دوباره آن. در ورود مجدد، بلوک remember دوباره اجرا شده و یک مقدار اولیه جدید ایجاد میکند.
remember وضعیت را در slot تابع Composable ذخیره میکند و تا زمانی که تابع در ترکیب است زنده میماند. ViewModel تا زمانی که lifecycle صفحه زنده است زنده میماند. ViewModel در چرخش حفظ میشود و برای منطق تجاری استفاده میشود. remember — برای وضعیت UI محلی که خارج از یک تابع نیاز نیست.
بله، remember در توابع @Preview Composable به درستی کار میکند، زیرا Preview یک CompositionContext کامل ایجاد میکند. با این حال، rememberSaveable ممکن است در Preview به درستی کار نکند، زیرا SavedStateHandle ممکن است در محیط پیشنمایش وجود نداشته باشد.
خلاصه
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید