Android Jetpack DataStore 101

Agung Kurniawan
Blibli.com Tech Blog
4 min readNov 29, 2021

--

DataStore Library just hit release version recently. Which is a good sign to implement it in our Project.

To quote google, data store 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 asynchronously, consistently, and transactionally.

Here is why we should use DataStore over the good old SharedPreference.

Prerequisites

Before we dive into main topic, let’s refresh our knowledge with stuff that’ll be used for DataStore.

Kotlin Coroutine

Kotlin Coroutine uses multi-threading workers but simpler & more lightweight compared to other thread library.

To use it on Android Project, add the following dependency on build.gradle.

We can switch to background thread with the following

Explanation:
- GlobalScope > scope where the coroutine is valid
- launch > behavior on how the work executed
- Dispatchers.Default > On which thread the work will be executed

For more information about Kotlin Coroutine, visit here

Flow

Coroutine component that can emit multiple values sequentially, as opposed of suspend function that only a single value.

As the flow emitting values, we can observe the value using livedata. There are shortcut method in livedata ktx that is asLiveData() to accomplish it. Add the following dependency.

Here’s an example of how flow works.

Notice that flow can only emit data with the same type as the flow.

DataStore will use flow as a way to emit the stored value. So learning how flow works is a plus value.

Preference DataStore + Tutorial

Preference DataStore are like traditional SharedPreference. It uses key + value pair to store the data. It’s not use predefined schema so it’s not type safety.

Here is how to implement:

First we have to add the dependency in build.gradle

Create reference to the datastore with property delegates to maintain the singleton

If we want to migrate from SharedPreference, add the following code when creating the reference

That’s it, we are good to go.

Read from DataStore

Define the key & data type using key type function. There are 7 function correspond with each primitive data type on kotlin

Read the value stored in DataStore.data using flow

Transform to liveData to start observing the emitted value by flow

If we want to get the first value only, we can use first() function provided by flow. Pay attention that it’s a suspend method so we have to use coroutine

DataStore use the advantage of asynchronously read-write data. But we can use it Synchronously by using runBlocking function. It’s useful if we want to migrate the previous SharedPreference implementation that is still synchronous.

Write to DataStore

Use edit() method provided by DataStore to write/ save the value. Notice that edit() method is a suspend method, so we use the help of coroutine

To make it synchronously, same with read datastore

Proto DataStore + Tutorial

As quoted from google codelabs:

Proto DataStore defines the schema using Protocol buffers. Using Protobufs allows persisting strongly typed data. They are faster, smaller, simpler, and less ambiguous than XML and other similar data formats. While Proto DataStore requires you to learn a new serialization mechanism, we believe that the strongly typed advantage brought by Proto DataStore is worth it.

Proto DataStore addressing the problem in which both SharedPreference & Preference DataStore is not. That is type safety. Proto DataStore use predefined schema to define the stored data type.

Implementation

To implement the proto DataStore & allow protobuf generate the schema, we need to add the following dependency and some change in build.gradle

Create the proto file in /app/src/main/proto folder

Type your scheme based on your needs.

Explanation:
- syntax → is what proto version we are using. i’d recommend proto3 as it has proper support
- option → to further config the generated scheme
- option java_package → to define the package of the generated scheme
- option java_multiple_files → define if the given value is true, then the generated scheme won’t be nested by outer class (see java_outer_classname option)
- message → object in java. Like in java, we can use object variable.
- string → string in java
- int32 → integer in java
- int64 → long in java
- repeated → for list type of data

To learn more about the proto syntax, click here

After we create the proto file, we need to rebuild the project so it will generate scheme.

Create a serializer

To tell the datastore how to read and write

Create the datastore by delegate function

To read the data from dataStore, no longer required preferenceKey and can just access the property of the object

To write into dataStore, we need to use updateData function and transform the preference to builder, set the data, and build to create new preference

Lastly, to migrate from SharedPreference to Proto DataStore, provide migration logic when creating the dataStore

Summary

SharedPreference good, DataStore is even better.
start use Preference DataStore, if speed is your thing, implement Proto DataStore.

Preference

https://developer.android.com/topic/libraries/architecture/datastore
https://developer.android.com/kotlin/coroutines

https://developer.android.com/kotlin/flow
https://developer.android.com/codelabs/android-proto-datastore

--

--

Agung Kurniawan
Blibli.com Tech Blog

Man of Rebahan. Master of Procrastination. Highest Degree of Missing Gold Opportunity.