خدافظی با SharedPreferences - آموزش DataStore در اندروید

DataStore در اندروید
DataStore در اندروید


دیتا استور چیه؟

دیتا استور(DataStore) کامپوننت جدید Jetpack که قرار جایگزین SharedPreferences بشه، طبیعتا نو که بیاد به بازار یه سری ویژگی های جدید داره، بهترین ویژگی که دیتا استور نسبت به شردپرفرنسز داره اینه که خوندن و نوشتن دیتا به صورت Async و با Flow که کامپوننتی از Kotlin Coroutines هست انجام میشه. چندتا نکته که قبل از ادامه دادن باید بدونید اینه که:

  • دیتا استور در این زمان که این پست نوشته میشه تو حالت آلفا قرار داره که برای استفاده در پروداکشن مناسب نیست.
  • قراره ما با کاتلین کد بزنیم
  • ما از Kotlin Coroutines استفاده میکنیم(خیلی سطح پایین)
  • همچنین از Kotlin Extension هم استفاده شده
  • برای UI برنامه از Jetpack Compose استفاده شده

چطور ازش استفاده کنیم

مرحله اول - کتابخونه رو به پروژه اضافه میکنیم:

implementation &quotandroidx.datastore:datastore-preferences:1.0.0-alpha02&quot

مرحله دوم - ساخت یک نمونه از دیتا استور:

private val dataStore by lazy { context.createDataStore(name = &quotdata_store&quot) }

مرحله سوم - خوندن و نوشتن:

دیتا استور هم مثل شردپرفرنسز داده ها رو به صورت key-value سازماندهی میکنه، اما موضوع برای دیتا استور یکم فرق داره اونم اینه که مثل شردپرفرنسز key ها به صورت string نیستن بلکه اونا باید از نوع Preferences.Key باشن(جلوتر مسئله روشن‌تر میشه) و موضوع دیگه ای هم که هست اگه بخوایم دیتایی رو توی دیتا استور ذخیره کنیم حتما باید از کوروتین کاتلین استفاده کینم، که در ساده ترین حالت فرآیند ذخیره کردن به شکل زیر هست:

GlobalScope.launch {
    val TEXT_KEY = preferencesKey<String>(&quottext&quot)
    dataStore.edit {
        it[TEXT_KEY] = &quotThis is just a simple text&quot
    }
}

درست مثل شردپرفرنسز تو خط دوم یک کلید برای ذخیره کردن دیتامون ساختیم به اسم TEXT_KEY و خط های بعدی دیتا رو توی دیتا استور ذخیره میکنه

وقتی بخوایم داده هایی رو که قبلا ذخیره شدن رو از دیتا استور بخونیم، ما اون دیتا رو در قالب Flow دریافت میکنیم مثل کد زیر:

val text: Flow<String> = dataStore.data.map { data ->
    data[key] ?: &quotDefault value&quot // if the data is null we'll get the &quotDefault value&quot text
}

text.collect { data ->
    println(&quotdata is: $data&quot)
}

درسته یکم عجیب غریب به نظر میاد برای همین همونطوری که بالاتر قید شد برای اینکه کار با دیتا استور راحت‌تر و خوانایی کدها بالاتر بره یه سری Extension Function به سورس‌کدمون اضافه کردیم

@InternalCoroutinesApi
fun <T> DataStore<Preferences>.liveData(key: Preferences.Key<T>, defaultValue: T): LiveData<T> =
    data.map {
        it[key] ?: defaultValue // if the data is null we'll get the defaultValue
    }.asLiveData(IO)

fun <T> DataStore<Preferences>.saveData(data: Pair<Preferences.Key<T>, T>) = GlobalScope.launch {
    edit {
        it[data.first] = data.second
    }
}

فانکشن اول دیتای ذخیره شده تو دیتا استور رو به صورت LiveData به ما میده که نهایتا نحوه خوندن از دیتا استور رو آسونتر میکنه:

val textLiveData: LiveData<String> = dataStore.liveData(TEXT_KEY, &quotnot specified yet&quot) // &quotnot specified yet&quot is the default value

همینطور نحوه استفاده از فانکشن دوم:

dataStore.saveData(TEXT_KEY to &quotThis text is gonna be saved in data store&quot)

در نهایت کد کامل اکتیویتی:

class MainActivity : AppCompatActivity() {

    private val dataStore by lazy { createDataStore(name = &quotdata_store&quot) }

    @InternalCoroutinesApi
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val textLiveData: LiveData<String> = dataStore.liveData(TEXT_KEY, &quotnull&quot)

        setContent {
            AppScreen(
                textLiveData = textLiveData,
                onSaveClicked = { saveText(it) }
            )
        }
    }

    private fun saveText(value: String) = dataStore.saveData(TEXT_KEY to value)

    companion object {
        private val TEXT_KEY = preferencesKey<String>(&quottext&quot)
    }

میتونید کد کامل رو از گیت دریافت کنید