Proto DataStore in Android: How to Store Complex Objects with Protocol Buffers

Table of Contents

Managing data on Android has evolved significantly over the years. From SharedPreferences to Room, we’ve seen the full spectrum. But when it comes to storing structured, complex data in a lightweight and efficient way, Proto DataStore steps in as a game-changer.

In this blog, we’ll walk through Proto DataStore, how it works under the hood, and how to use it with Protocol Buffers to store complex objects. We’ll also look at how it stacks up against the older SharedPreferences and why it’s the better modern choice.

Let’s break it down step by step.

What is Proto DataStore?

Proto DataStore is a Jetpack library from Google that helps you store typed objects persistently using Protocol Buffers (protobuf), a fast and efficient serialization format.

It’s:

  • Type-safe
  • Asynchronous
  • Corruption-resistant
  • Better than SharedPreferences

Unlike Preferences DataStore, which stores data in key-value pairs (similar to SharedPreferences), Proto DataStore is ideal for storing structured data models.

Why Use Proto DataStore?

Here’s why developers love Proto DataStore:

  • Strong typing — Your data models are generated and compiled, reducing runtime errors.
  • Speed — Protocol Buffers are faster and more compact than JSON or XML.
  • Safe and robust — Built-in corruption handling and data migration support.
  • Asynchronous API — Uses Kotlin coroutines and Flow, keeping your UI smooth.

Store Complex Objects with Proto DataStore

Let’s go hands-on. Suppose you want to save a user profile with fields like name, email, age, and preferences.

Step 1: Add the Dependencies

Add these to your build.gradle (app-level):

Kotlin
dependencies {
    implementation "androidx.datastore:datastore:1.1.0"
    implementation "androidx.datastore:datastore-core:1.1.0"
    implementation "com.google.protobuf:protobuf-javalite:3.25.1"
}

In your build.gradle (project-level), enable Protobuf:

Kotlin
protobuf {
    protoc {
        artifact = "com.google.protobuf:protoc:3.25.1"
    }

    generateProtoTasks {
        all().each { task ->
            task.builtins {
                java { }
            }
        }
    }
}

Also apply plugins at the top:

Kotlin
plugins {
    id 'com.google.protobuf' version '0.9.4'
    id 'kotlin-kapt'
}

Step 2: Define Your .proto File

Create a file named user.proto inside src/main/proto/:

Kotlin
syntax = "proto3";

option java_package = "com.softaai.datastore";
option java_multiple_files = true;

message UserProfile {
  string name = 1;
  string email = 2;
  int32 age = 3;
  bool isDarkMode = 4;
}

This defines a structured data model for the user profile.

Step 3: Create the Serializer

Create a Kotlin class that implements Serializer<UserProfile>:

Kotlin
object UserProfileSerializer : Serializer<UserProfile> {
    override val defaultValue: UserProfile = UserProfile.getDefaultInstance()

    override suspend fun readFrom(input: InputStream): UserProfile {
        return UserProfile.parseFrom(input)
    }

    override suspend fun writeTo(t: UserProfile, output: OutputStream) {
        t.writeTo(output)
    }
}

This handles how the data is read and written to disk using protobuf.

Step 4: Initialize the Proto DataStore

Create a DataStore instance in your repository or a singleton:

Kotlin
val Context.userProfileDataStore: DataStore<UserProfile> by dataStore(
    fileName = "user_profile.pb",
    serializer = UserProfileSerializer
)

Now you can access this instance using context.userProfileDataStore.

Step 5: Read and Write Data

Here’s how you read the stored profile using Kotlin Flow:

Kotlin
val userProfileFlow: Flow<UserProfile> = context.userProfileDataStore.data

To update the profile:

Kotlin
suspend fun updateUserProfile(context: Context) {
    context.userProfileDataStore.updateData { currentProfile ->
        currentProfile.toBuilder()
            .setName("Amol Pawar")
            .setEmail("[email protected]")
            .setAge(28)
            .setIsDarkMode(true)
            .build()
    }
}

Easy, clean, and fully type-safe.

Bonus: Handling Corruption and Migration

Handle Corruption Gracefully

You can customize the corruption handler if needed:

Kotlin
val Context.safeUserProfileStore: DataStore<UserProfile> by dataStore(
    fileName = "user_profile.pb",
    serializer = UserProfileSerializer,
    corruptionHandler = ReplaceFileCorruptionHandler {
        UserProfile.getDefaultInstance()
    }
)

Migrate from SharedPreferences

If you’re switching from SharedPreferences:

Kotlin
val Context.migratedUserProfileStore: DataStore<UserProfile> by dataStore(
    fileName = "user_profile.pb",
    serializer = UserProfileSerializer,
    produceMigrations = { context ->
        listOf(SharedPreferencesMigration(context, "old_prefs_name"))
    }
)

When to Use Proto DataStore

Use Proto DataStore when:

  • You need to persist complex, structured data.
  • You care about performance and file size.
  • You want a modern, coroutine-based data solution.

Avoid it for relational data (instead use Room) or for simple flags (Preferences DataStore may suffice).

Conclusion

Proto DataStore is the future-forward way to store structured data in Android apps. With Protocol Buffers at its core, it combines speed, safety, and type-safety into one clean package.

Whether you’re building a user profile system, app settings, or configuration storage, Proto DataStore helps you stay efficient and future-ready.

TL;DR

Q: What is Proto DataStore in Android?
 A: Proto DataStore is a modern Jetpack library that uses Protocol Buffers to store structured, type-safe data asynchronously and persistently.

Q: How do I store complex objects using Proto DataStore?
 A: Define a .proto schema, set up a serializer, initialize the DataStore, and read/write using Flow and coroutines.

Q: Why is Proto DataStore better than SharedPreferences?
 A: It’s type-safe, faster, handles corruption, and integrates with Kotlin coroutines.

Skill Up: Software & AI Updates!

Receive our latest insights and updates directly to your inbox

Related Posts

error: Content is protected !!