remember — المفاهيم الأساسية، الحفاظ على القيم بين عمليات إعادة التركيب

المؤلف: IT Sectr نُشر: 2026-06-28 وقت القراءة: 8 دق

remember هي دالة في Jetpack Compose تتيح لك الحفاظ على قيمة بين عمليات إعادة التركيب، مما يمنع إعادة تعيين الحالة عند كل إعادة تشغيل لدالة Composable. بدون remember، جميع المتغيرات المعلنة داخل الدالة ستعاد تعيينها عند كل تحديث لواجهة المستخدم، مما يجعل الحالة غير مستقرة وعديمة الفائدة. وفقًا لـ Google Android Developers, 2026، الاستخدام الصحيح لـ remember هو أساس إدارة الحالة الصحيحة في واجهة المستخدم التصريحية.

الخلاصة

  • remember يحتفظ بقيمة في فتحة التركيب بين عمليات إعادة تركيب الدالة
  • المفاتيح في remember(key) تحدد متى يجب إعادة حساب القيمة
  • rememberSaveable يحتفظ بالقيمة عند تدوير الشاشة وتصغير التطبيق
  • derivedStateOf ينشئ حالة مشتقة، مما يحسن العمليات الحسابية أثناء إعادة التركيب
  • إعادة التعيين لـ remember تحدث فقط عند خروج الدالة من التركيب

ما هو remember في Jetpack Compose

remember هي دالة مدمجة في Jetpack Compose من حزمة androidx.compose.runtime تنشئ كائنًا يحتفظ بقيمته بين الاستدعاءات المتتالية لدالة Composable. تقنيًا، remember تعمل مع الفتحات — خلايا ذاكرة خاصة مخصصة لكل موضع استدعاء دالة في شجرة واجهة المستخدم. طالما بقيت الدالة في التركيب (لم تتم إزالتها عبر شرط if)، سيعيد remember القيمة المحفوظة عند كل إعادة تركيب.

صياغة remember بسيطة: داخل الأقواس المتعرجة يتم تحديد كتلة حساب القيمة الأولية. يتم تنفيذ الكتلة مرة واحدة فقط — أثناء التركيب الأول للدالة. جميع عمليات إعادة التركيب اللاحقة تعيد القيمة المحفوظة بالفعل دون إعادة تنفيذ الكتلة. ومع ذلك، إذا تم تحديد معامل مفتاح، يتم إعادة تنفيذ الكتلة عند تغير المفتاح، مما يسمح بإعادة حساب القيمة بناءً على بيانات الإدخال.

remember ليس سحرًا في Kotlin — إنها دالة بسيطة بمعامل مفتاح ولامدا حسابية. يستخدم تنفيذها الداخلي Composer للقراءة والكتابة في الفتحات. يقوم مترجم Kotlin، عند رؤية استدعاء remember، بتوليد كود يصل إلى CompositionContext الحالي ويدير الفتحات. هذا يعني أن remember يمكن استدعاؤه فقط داخل دالة Composable أو دالة أخرى في سياق التركيب.

أنواع remember: remember، rememberSaveable، derivedStateOf

في Jetpack Compose، هناك ثلاثة أنواع رئيسية من remember، لكل منها غرضه الخاص. remember الأساسي يحتفظ بالقيمة فقط في ذاكرة العملية الحالية — عند تدوير الشاشة (تغيير الإعدادات)، يعيد Compose إنشاء التركيب ويتم إعادة تعيين جميع قيم remember. للحفاظ على البيانات أثناء تغييرات الإعدادات وإيقاف العملية يتم استخدام rememberSaveable.

rememberSaveable يسلسل القيمة في Bundle عبر آلية SavedStateHandle أو Parcelable. هذا يسمح بالبقاء على قيد الحياة عند تدوير الشاشة، إعداد "عدم الاحتفاظ بالأنشطة" وحتى تصغير التطبيق المؤقت. ومع ذلك، يفرض rememberSaveable قيودًا على نوع البيانات التي يمكن تخزينها: يجب أن تكون بدائية أو Parcelable أو Serializable أو تدعم محول Saver.

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

kotlin
@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 يعتمد على مدى أهمية الحفاظ على البيانات أثناء تغييرات الإعدادات. للحالات المؤقتة التي ليس من المهم فقدانها عند التدوير (الرسوم المتحركة، موضع التمرير الحالي، حالة التركيز) — remember العادي كافٍ. للبيانات الحيوية (نص في النموذج، العناصر المحددة، مربعات الاختيار) — استخدم rememberSaveable.

الأداء: rememberSaveable أبطأ من remember العادي لأنه يتطلب تسلسلاً في Bundle. استخدم rememberSaveable فقط للبيانات التي تحتاج حقًا للبقاء على قيد الحياة عند إعادة إنشاء Activity. لكل شيء آخر — remember بسيط. الاستخدام المفرط لـ rememberSaveable يؤدي إلى بطء عند تدوير الشاشة والتبديل بين التطبيقات.

إذا كنت تعمل مع فئات لا تدعم Parcelable أو Serializable، استخدم Saver — محول يحدد كيفية حفظ واستعادة الكائن. يتم وصف Saver بزوج من اللامدا: save (يحول الكائن إلى نوع قابل للتخزين) و restore (يستعيد الكائن من البيانات المحفوظة). يوجد Saver قياسي مطبق بالفعل لـ mutableStateListOf و mutableStateMapOf.

الخاصيةrememberrememberSaveable
الحفظ أثناء إعادة التركيبنعمنعم
الحفظ عند التدويرلانعم
الحفظ عند إيقاف العمليةلانعم
متطلبات النوعأيParcelable، Serializable، Saver
الأداءعاليمتوسط

أمثلة على استخدام remember في المشاريع الحقيقية

لنفكر في سيناريو نموذجي — شاشة تحرير الملف الشخصي حيث يتم استخدام remember لعدة أغراض: تخزين حالة حقول النموذج، حساب القيم المشتقة، وتخزين العمليات الحسابية المكلفة في الذاكرة المؤقتة.

kotlin
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، وليس عند كل إعادة تركيب.

الحالات المشتقة و remember مع المفاتيح

الحالات المشتقة هي قيم يتم حسابها من كائنات State أخرى. بدلاً من حسابها عند كل إعادة تركيب وإهدار وحدة المعالجة المركزية على نتائج متطابقة، remember مع derivedStateOf يحسب القيمة فقط عندما تتغير المصادر. هذا مفيد بشكل خاص للتصفية والفرز وتجميع البيانات.

remember مع المفاتيح (remember(key) { calculation }) هي آلية تحسين أخرى. إذا لم يتغير المفتاح منذ آخر إعادة تركيب، لا يتم تنفيذ كتلة الحساب ويتم إرجاع القيمة المخزنة مؤقتًا. هذا مناسب لتخزين الكائنات التي يكون إنشاؤها مكلفًا: تنسيق التواريخ، تحليل JSON، إنشاء مجموعات كبيرة غير قابلة للتغيير.

kotlin
@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 خارج دالة Composable؟

لا، remember هي دالة من حزمة compose.runtime تتطلب CompositionContext. يمكن استدعاؤها فقط داخل دالة @Composable أو داخل دالة أخرى تم استدعاؤها من Composable. لتخزين البيانات خارج التركيب، استخدم ViewModel.

ماذا يحدث إذا لم أحدد مفتاحًا في remember؟

بدون مفتاح، remember ينفذ كتلة الحساب مرة واحدة فقط — أثناء التركيب الأول. جميع عمليات إعادة التركيب اللاحقة تعيد القيمة المحفوظة. إذا كنت بحاجة إلى إعادة حساب القيمة عند تغير البيانات، تأكد من تحديدها كمفتاح: remember(data) { compute(data) }.

كيف يمكن إعادة تعيين remember بالقوة؟

لا توجد طريقة مباشرة لإعادة تعيين remember. الطريقة الوحيدة هي إزالة الدالة من التركيب (على سبيل المثال، إخفاؤها بشرط if) ثم إظهارها مرة أخرى. عند إعادة الدخول، يتم تنفيذ كتلة remember مرة أخرى، مما ينشئ قيمة أولية جديدة.

ما الفرق بين remember و ViewModel؟

remember يخزن الحالة في فتحة دالة Composable ويعيش طالما أن الدالة في التركيب. ViewModel يعيش طالما يعيش دورة حياة الشاشة. ViewModel يتم حفظه عند التدوير ويستخدم للمنطق التجاري. remember مخصص لحالة UI المحلية التي لا تحتاج إلى خارج دالة واحدة.

هل يعمل remember في مكونات Preview؟

نعم، remember يعمل بشكل صحيح في دوال @Preview Composable لأن Preview ينشئ CompositionContext كامل. ومع ذلك، قد لا يعمل rememberSaveable بشكل صحيح في Preview لأن SavedStateHandle قد يكون غائبًا في بيئة المعاينة.

الملخص

  • remember يحتفظ بقيمة في فتحة التركيب ويبقى على قيد الحياة عبر عمليات إعادة تركيب الدالة
  • rememberSaveable يحتفظ أيضًا بالقيمة عند تدوير الشاشة وإيقاف العملية
  • derivedStateOf ينشئ حالة مشتقة بحسابات كسولة
  • المفاتيح في remember(key) تتحكم في إعادة حساب القيمة المخزنة مؤقتًا
  • إعادة التعيين لـ remember تحدث فقط عند إزالة الدالة من التركيب
  • الأداء: derivedStateOf والمفاتيح تمنع الحسابات غير الضرورية أثناء إعادة التركيب
  • توصية: استخدم rememberSaveable لحقول الإدخال و remember + derivedStateOf للقيم المحسوبة

سنقوم بتطوير تطبيق جوال جاهز

تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.

مناقشة المشروع

اقرأ أيضًا