Sign in
Log inSign up

Preferences DataStore

Everything You Need to Know🤓🤓

kevin kenei's photo
kevin kenei
·Dec 27, 2021·

3 min read

Preferences DataStore

Photo by Christian Egli on Unsplash

What is Jetpack DataStore?🤷‍♂️

Jetpack DataStore is a data storage solution that allows you to store key-value pairs or typed objects with protocol buffers. DataStore uses Kotlin coroutines and Flow to store data reliably, asynchronously and consistently.

DataStore is ideal for small, simple datasets so If you need to support large or complex datasets, partial updates, or referential integrity, consider using Room instead of DataStore.

DataStore provides two different implementations:

Preferences DataStore and Proto DataStore:

Proto DataStore stores typed objects while Preferences DataStore stores key-value pairs.

Data is stored asynchronously, consistently, and transactionally, overcoming some of the drawbacks of SharedPreferences. This article focuses on Preferences DataStore.

What you will build👨🏻‍💻

In this article we will learn Preferences DataStore by building a simple app that takes in and saves a key value pairs, then we can use saved keys to read their values.

Screenshot_20211227-140536.png

When we press the save button entered key 1 from the first textField and Entered value from the second are saved in the datastore, Hence we can now get the value from our prefereces by entering its associated key and pressing the read button and displaying it as text below the read button.

1. Getting set up🧰

To get you started as quickly as possible, I have prepared a starter project for us to build on here on the master branch. Where I have only added the layout xml in activity_main, setting up ViewBinding in our MainActivity and added the needed coroutines and datastore dependencies.

Lets create a datastore object before onCreate on our MainActivity

  //datastore object
  private lateinit var dataStore: DataStore<Preferences>

then in OnCreate we can asign our dataStore to CreateDataStore

    //
    dataStore = createDataStore(name = "settings")

2. Saving to PreferencesDataStore 💾

Lets create a suspend function save which takes in a key and value to save data .

       //save into data store
       private suspend fun save(key:String, value:String){
         val dataStoreKey = preferencesKey<String>(key)
      dataStore.edit { settings->
          settings[dataStoreKey] = value
       }
      }

In the save function we specify a key that PreferencesDataStore uses and pass in our key in it

        val dataStoreKey = preferencesKey<String>(key)

Where we can now add code to write something in our dataStore instance.

    dataStore.edit { settings->
              settings[dataStoreKey] = value
            }

datastore.edit{}

is a suspend fuction where we have reference to mutable preferences which we name settings and set it to our value

3. Reading from PreferencesDataStore🧐

  //save into data store
     private suspend fun read(key:String):String?{
    val dataStoreKey = preferencesKey<String>(key)
    val preferences = dataStore.data.first()
    return preferences[dataStoreKey]
 }

We create a function to read from our dataStore which only needs the key and returns a String which is the value read from the key and returns null if it does not exist.

We also need dataStoreKey to read our values from datastore

     val dataStoreKey = preferencesKey<String>(key)

👏👏We can now get the preferences from which we can now read our actual values as flow of preferences and since the flow emits that single preference object we use .first() to return the first emition of the flow,from which we can now return our actual data.

3. Finishing Up

Now in OnCreate we can setUp our views. We have a button that saves data to from our key and value edit texts to datastore. Which we launch in a lifecycle scope because we execute it in a coroutine

  binding.btnSave.setOnClickListener {
        lifecycleScope.launch {
            save(
                binding.etSaveKey.text.toString(),
                binding.etSaveValue.text.toString()
            )
        }
       }

And set onclickListener on the read button and assign text of our tvReadValue to what we got from our read function

   binding.btnRead.setOnClickListener {
        lifecycleScope.launch {
          val value = read(binding.etReadkey.text.toString())
            binding.tvReadValue.text = value ?: "No Value Found"
        }
    }

congratulations!!🥳🥳

If you now run the app we can enter our key value pairs and access our values with the specific keys. You can get the final source code here .See you in the next article.🙋‍♂️🙋‍♂️