DataStore and synchronous work

Simona Milanović
Android Developers
2 min readFeb 10, 2022

--

In the following posts from our Jetpack DataStore series, we will cover several additional concepts to understand how DataStore interacts with other APIs, so that you’d have everything at your disposal to use it in a production environment. In this post specifically, we will be focusing on doing synchronous work with DataStore. We will be referring to the Preferences codelab, for code samples.

Doing synchronous work

Throughout this series, we’ve mentioned DataStore’s fully asynchronous API, coming from its internal usage of Kotlin coroutines and Flow. To prevent potential ANRs and UI jank happening when heavier I/O operations are done on the UI thread, DataStore does not offer ready-to-use synchronous support. DataStore saves its dataset in a file and under-the-hood performs all data operations on Dispatchers.IO, unless specified otherwise, keeping your UI thread unblocked. This API structure is one of the main advantages of DataStore over its predecessor SharedPreferences and how you’d use DataStore in the majority of cases.

However, if you find that your code requires you to work synchronously with DataStore, whether it’s because of a dependency to another API running on the main thread or because your current setup requires you retrieve some persisted values for your UI setup, you could use runBlocking() coroutine builder to read DataStore synchronously. This will block the calling thread until DataStore returns:

If you find yourself in a situation where you need to use this approach, do spend some time figuring out if it’s absolutely necessary to block the main thread. Think about how you could use the provided DataStore async alternatives or refactor your current code to avoid runBlocking(), for example by preloading the data asynchronously:

If this isn’t possible, make sure you cover all potential UI jank scenarios with error handling, cancellation and timeouts or some nice visuals to make the user experience as smooth as possible.

To be continued

We’ve covered how to perform synchronous work with DataStore. Although this isn’t the recommended approach for DataStore, if your current setup does require you to make synchronous calls to it, you can use use .runBlocking() combined with .first() operator.

Join us for the next post in the series where we will be looking into how to do DataStore-to-DataStore migrations.

You can find all posts from our Jetpack DataStore series here:
Introduction to Jetpack DataStore
All about Preferences DataStore
All about Proto DataStore
DataStore and dependency injection
DataStore and Kotlin serialization
DataStore and synchronous work
DataStore and data migration
DataStore and testing

--

--

Simona Milanović
Android Developers

Android Developer Relations Engineer @Google, working on Jetpack Compose