DataStore and data migration

Simona Milanović
Android Developers
3 min readFeb 15, 2022

--

In this post from our Jetpack DataStore series, we will be covering how to do DataStore-to-DataStore migrations. Hopefully, this will provide you all the information you need to add DataStore to your app successfully. We will be referring to the Preferences codelab throughout this post, for code samples.

Data migration

We previously talked about migrating from SharedPreferences to DataStore, using the SharedPreferencesMigration. However, it is likely that at some point you will also need to do a DataStore-to-DataStore migration, for example when you make some significant changes to your dataset (like renaming your data model values or changing their type).

This process is very similar to the migration from SharedPreferences. In fact, SharedPreferencesMigration is just an implementation of the DataMigration interface:

To understand how to use DataMigration, let’s break this down:

  • DataMigration<T> — our interface for migrations to DataStore. Methods on this migration (shouldMigrate, migrate and cleanUp) may be called multiple times if DataStore encounters issues when writing the newly migrated data to disk or if any of the migrations throws an Exception .
  • shouldMigrate()— specifies whether this migration needs to be performed. If this returns false, no migration or cleanup will occur. This will be called every time the DataStore is initialized.
  • migrate() — performs the migration. If it fails, DataStore will not commit any data to disk, cleanUp() will not be called, and the exception will be propagated back to the DataStore call that triggered the migration. Future calls to DataStore will result in migration being attempted again. Note that this will always be called before a call to cleanUp() .
  • cleanUp()—where you’d add your implementation for clearing any old data from the previous storage that was migrated into the new DataStore. This will not be called if the migration fails. If cleanUp() throws an exception, the exception will be propagated back to the DataStore call that triggered the migration and future calls to DataStore will result in migration being attempted again.

Preferences DataStore migration

In order to create an implementation that would suit our migration needs, let’s imagine a scenario where we’d want to migrate from oldPreferencesDataStore to newPreferencesDataStore. We want to:

  1. Remap and rename one specific old Float key-value pair to a new Int one
  2. Migrate all other key-value pairs from old to new as they are
  3. Clean up the old storage

For simplicity, we will do all this in our TasksActivity of the Preferences codelab using the Preference DataStore delegates, but you can follow the instructions on Hilt injection to move this into an injection module.

We implement DataMigration and override its functions in the following manner:

produceMigrations will ensure that the migrate() is run before any potential data access to the new DataStore. This means your migration must have succeeded before DataStore emits any further values and before it begins making any new changes to the data.

As the produceMigrations parameter takes in a list of DataMigrations, you could transfer from as many old storages as you’d like. That is all it takes to migrate your data safely! You can easily follow the same pattern to migrate Proto to Proto DataStore — the only difference would be in how you’d transform the data.

To be continued

We’ve covered performing data migrations from different DataStores — how the DataMigration interface works, how to override its functions to transform your old data to new, migrate it and then clean up accordingly.

Join us for the next and final post in the series where we will be looking into how to test DataStore.

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