كيفية تخزين واسترجاع الإعدادات في تطبيق Compose باستخدام DataStore بديل SharedPreferences

ربط DataStore بـ ViewModel في Compose للحصول على أداء أسرع
إنشاء نظام حفظ بيانات المستخدم في كوتلن كومبوز باستخدام DataStore

لا تفقد بياناتك بعد الآن! تعلم كيفية استخدام DataStore في Jetpack Compose

في تطوير تطبيقات Android الحديثة، يعد تخزين البيانات المحلية أمرًا مهما لضمان أن بيانات المستخدم آمنة وفعالة. ومن بين الأدوات المستخدمة لتخزين البيانات Jetpack DataStore، والذي يعتبر بديلاً حديثًا وأقوى لـ SharedPreferences. بالإضافة إلى الهيلت الذي يسهل عملية حقن Dependency وJetpack Compose لتصميم واجهة المستخدم، يمكنك إنشاء تطبيق متكامل وحديث.


ما هو Jetpack DataStore؟

DataStore عبارة عن واجهة برمجة تطبيقات جديدة لتخزين بيانات Android تُستخدم لتخزين البيانات بشكل دائم وآمن. إنه أسرع وأكثر أمانًا من SharedPreferences ويمكن استخدامه بطريقتين: Preferences DataStore لتخزين القيم البسيطة مثل النصوص والأرقام، وProto DataStore لتخزين البيانات المعقدة باستخدام Protocol Buffers.


خطوات إعداد DataStore باستخدام Hilt وJetpack Compose

تكوين DataStore على Android

في الكود المحدد، يتم استخدام Preferences DataStore لتخزين بيانات المستخدم. يتم تخصيص DataStore عبر تفضيلات DataStore كما هو موضح في هذا القسم:

سنقوم هنا بإنشاء DataStore يسمى "SampleData"، والذي سيتم استخدامه لتخزين البيانات. يربط الرمز DataStore بالسياق ليسهل الوصول إليه في أي مكان.

تخزين البيانات مع DataStore لتخزين اسم المستخدم، نستخدم طريقة setUserName في فئة DataStorePreferenceRepository. هنا يتم إنشاء مفتاح باستخدام stringPreferencesKey المرتبط بالمفتاح الذي سنمرره، ثم نقوم بتحرير البيانات وتخزين اسم المستخدم.

لاسترداد اسم المستخدم المُخزن، نستخدم الدالة getUserName التي تُرجع دفقًا من البيانات:

هنا تتم معالجة البيانات من خلال التدفق، مما يسمح لنا بمراقبة التغييرات في البيانات مباشرة.


تطبيق مذكرات (Notes) بحفظ البيانات باستخدام DataStoreفي Jetpack Compose


@Singleton
class DataStorePreferenceRepository @Inject constructor(
    @ApplicationContext context: Context
) {
    private val dataStore: DataStore<Preferences> = context.dataStore

    companion object {
        val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "SampleData")
    }

    suspend fun setUserName(key: String, userName: String) {
        val prefKey = stringPreferencesKey(key)
        dataStore.edit { preferences ->
            preferences[prefKey] = userName
        }
    }

    fun getUserName(key: String): Flow<String> {
        val prefKey = stringPreferencesKey(key)
        return dataStore.data.map { preferences ->
            preferences[prefKey] ?: ""
        }
    }
}

قم بإنشاء فئة DataStorePreferenceRepository

تم الإعلان عن فئة DataStorePreferenceRepository باعتبارها فئة Singleton باستخدامSingleton ويتم إجراء حقن التبعية باستخدام Hilt عبرInject. بهذه الطريقة نضمن وجود مثيل واحد فقط للفئة خلال عمر التطبيق:


ViewModel

في جزء ViewModel، نقوم بفصل منطق التطبيق عن واجهة المستخدم باستخدام ViewModel، وهو أحد أهم مكونات MVVM (Model-View-ViewModel). هنا، يتم استخدام Hilt لحقن التبعية بطريقة تسهل إدارة البيانات المخزنة في DataStore في التطبيق. نشرح الخطوات والتفاصيل بشكل أكثر وضوحا


@HiltViewModel
class DataViewModel @Inject constructor(
    private val dataStorePreferenceRepository: DataStorePreferenceRepository
) : ViewModel() {

    private val _state = MutableStateFlow(DataUiState())
    val state: StateFlow<DataUiState> = _state.asStateFlow()

    fun updateUserName(newName: String) {
        _state.update {
            it.copy(userName = newName)
        }
    }

    fun saveUserName(key: String, userName: String) {
        viewModelScope.launch {
            dataStorePreferenceRepository.setUserName(key, userName)
            _state.update {
                it.copy(userName = userName)
            }
        }
    }

    fun getUserName(key: String) {
        viewModelScope.launch {
            dataStorePreferenceRepository.getUserName(key).collect { userName ->
                _state.update {
                    it.copy(userName = userName)
                }
            }
        }
    }
}


Jetpack Compose: إنشاء واجهة تفاعلية

في هذا المثال، نستخدم Jetpack Compose لإنشاء واجهة المستخدم التي تتضمن TextField لتخزين اسم المستخدم وزرًا لتخزين الاسم.

عند إدخال اسم المستخدم في حقل النص والضغط على زر إرسال، يتم حفظ الاسم في DataStore من خلال استدعاء saveUserName، ثم يتم عرض الاسم المحفوظ على الشاشة.


@Composable
fun DataStoreInput(
    viewModel: DataViewModel = hiltViewModel()
) {
    val state by viewModel.state.collectAsState()
    val userName = state.userName

    val textState = remember { mutableStateOf(TextFieldValue()) }
    val scope = rememberCoroutineScope()

    LaunchedEffect(key1 = userName) {
        viewModel.getUserName("name")
    }


    Column(
        modifier = Modifier.fillMaxSize()
    ) {
        Column(
            modifier = Modifier
                .fillMaxWidth()
                .background(Color.Green)
                .height(50.dp),
            horizontalAlignment = Alignment.CenterHorizontally,
            verticalArrangement = Arrangement.Center
        ) {
            Text(
                text = "DataStore Preference",
                color = Color.White,
                fontSize = 20.sp,
                fontWeight = FontWeight.Bold
            )
        }

        Column(
            modifier = Modifier.fillMaxSize()
        ) {
            Column(
                modifier = Modifier
                    .fillMaxWidth()
                    .background(Color.Green)
                    .height(50.dp),
                horizontalAlignment = Alignment.CenterHorizontally,
                verticalArrangement = Arrangement.Center
            ) {
                Text(
                    text = "DataStore Preference",
                    color = Color.White,
                    fontSize = 20.sp,
                    fontWeight = FontWeight.Bold
                )
            }

            Column(
                modifier = Modifier
                    .fillMaxSize(),
                horizontalAlignment = Alignment.CenterHorizontally
            ) {
                Spacer(modifier = Modifier.height(30.dp))

                // TextField لادخال اسم المستخدم
                OutlinedTextField(
                    value = textState.value,
                    onValueChange = { textState.value = it },
                    label = { Text(text = "Enter User Name", fontSize = 15.sp) },
                    modifier = Modifier.fillMaxWidth(0.7f),
                    keyboardOptions = KeyboardOptions(
                        keyboardType = KeyboardType.Text
                    )
                )

                Spacer(modifier = Modifier.height(20.dp))

                // زر لحفظ اسم المستخدم
                Button(
                    onClick = {
                        scope.launch {
                            viewModel.saveUserName("name", textState.value.text)
                        }
                    },
                    shape = RoundedCornerShape(8.dp),
                    elevation = ButtonDefaults.elevatedButtonElevation(
                        defaultElevation = 6.dp,
                        pressedElevation = 8.dp,
                        disabledElevation = 0.dp
                    ),
                    modifier = Modifier.padding(5.dp)
                ) {
                    Text(
                        text = "Submit",
                        modifier = Modifier.padding(6.dp)
                    )
                }

                Spacer(modifier = Modifier.height(30.dp))

                Text(
                    text = userName,
                    fontWeight = FontWeight.Bold,
                    color = Color.Black,
                    fontSize = 20.sp
                )
            }
        }
    }
}

تعليقات