Android Proto DataStore – Ought to You Use It?

A number of years again, Google introduced the DataStore, which is a substitute for the tried and true SharedPreferences.
For those who use or have used SharedPreferences in your purposes, you is perhaps pondering of constructing the change. However as with every little thing, the principle query right here is: what’s going to be the associated fee in improvement?
There are benefits for utilizing DataStore, however solely the Proto DataStore lets you save objects whereas offering kind security.
For those who take a look at the documentation for Proto DataStore, you will see that that it’s a bit outdated and lacking some essential steps when working with it. So that’s the reason, on this article, we’re going to go over methods to combine Proto DataStore into your software and present that it’s not that large of a trouble to make use of it.
What’s DataStore?
Jetpack DataStore has two variants:
- Preferences DataStore
- Proto DataStore
We received’t be discussing the primary, as a consequence of it’s similarity to SharedPreferences and likewise the truth that is has been coated extensively. So now let’s perceive what the Proto in Proto DataStore means.
Proto is the identify Google selected to signify Protocol Buffers. These are (Google’s) mechanism that enable you serialize structured knowledge. They aren’t coding language-specific and normally, you outline the kind of knowledge that you simply want to work with after which code is generated that helps you learn and write your knowledge.
We will probably be utilizing the Proto 3 model on this article.
How does that definition seem like?
message MyItem {
string itemName = 1;
int32 itemId = 2;
}
First, you outline an object with the message key phrase. Inside it, you listing the fields related to that object. The numbers on the finish of every subject are used to determine the sector itself and can’t be modified as soon as being set and the article is in use.
However what if we wished to have a number of objects in our .proto file? Assuming the objects are associated to at least one one other, you are able to do this just by including extra message objects:
message MyItem {
string itemName = 1;
int32 itemId = 2;
}
message MyListOfItems {
repeated MyItem gadgets = 1;
}
Discover that above we’ve added one other message object that depends on the MyItem object outlined above. If you wish to outline an inventory of objects, it is advisable to use the repeated key phrase.
Find out how to Set Up Proto DataStore
To get began, you will want so as to add the next dependencies to your software stage construct.gradle:
implementation "androidx.datastore:datastore-preferences:1.0.0"
implementation "com.google.protobuf:protobuf-javalite:3.18.0"
Then, you’ll need to create a proto listing inside your venture. This listing must be a sibling of the Java folder in your venture construction.
Inside the proto listing, you may be making a .proto file. This file is answerable for producing the info sorts you want to retailer in Proto DataStore.
Contained in the proto listing, create a file with the .proto extension. Our .proto file will maintain objects representing a Todo listing (what else?). So we are going to name our file todo.proto and it’ll seem like this:
syntax = "proto3";
possibility java_package = "com.yourPackageName.todo";
possibility java_multiple_files = true;
message TodoItem {
string itemId = 1;
string itemDescription = 2;
}
message TodoItems {
repeated TodoItem gadgets = 1;
}
Discover how we outlined two message objects:
- TodoItem – that defines a todo merchandise
- TodoItems – that defines an inventory of TodoItem objects
Subsequent, construct the venture in order that courses will probably be generated for TodoItem and TodoItems.
After our knowledge objects have been outlined, we have to create a category to serialize them. This class will inform the DataStore methods to learn/write our objects.
object TodoItemSerializer: Serializer<TodoItems> {
override val defaultValue: TodoItems = TodoItems.getDefaultInstance()
override droop enjoyable readFrom(enter: InputStream): TodoItems {
attempt {
return TodoItems.parseFrom(enter)
} catch (exception: InvalidProtocolBufferException) {
throw CorruptionException("Can't learn proto.", exception)
}
}
override droop enjoyable writeTo(
t: TodoItems,
output: OutputStream
) = t.writeTo(output)
}
Let’s evaluation what we’ve on this class:
- Once we declare the category, we have to implement the Serializer interface with our object as the kind (T)
- We outline a default worth for the serializer in case the file isn’t created
- We override the readFrom/writeTo strategies and we ensure to have our object as the info kind there
We’ve got our .proto file with our knowledge sorts and our serializer, so the following step is to instantiate the DataStore. We do that by utilizing the property delegate created by dataStore, which requires giving a filename the place our knowledge will probably be saved and our serializer class (which we outlined above).
personal const val DATA_STORE_FILE_NAME = "todo.pb"
personal val Context.todoItemDatastore: DataStore<TodoItems> by dataStore(
fileName = DATA_STORE_FILE_NAME,
serializer = TodoItemSerializer,
)
This piece of code must reside on the high of a category of your selecting above the definition of the category itself. That’s:
personal const val DATA_STORE_FILE_NAME = "todo.pb"
personal val Context.todoItemDatastore: DataStore<TodoItems> by dataStore(
fileName = DATA_STORE_FILE_NAME,
serializer = TodoItemSerializer,
)
class YourClassName {
}
To entry this object in the remainder of our software, we might want to use a context. An instance is to make use of the appliance context in your viewmodel class:
class MyViewModel(software: Utility): AndroidViewModel(software) {
val todoDataStore = software.todoItemDataStore
}
Find out how to Use Kotlin Movement
Now that we’ve gone by establishing every little thing we want for our DataStore, we’ll focus on how we are literally going to work together with it. We’ll need to learn and write knowledge to/from it. However the best way we will accomplish that is completely different from what chances are you’ll be accustomed to from SharedPreferences.
The DataStore we outlined above has an information subject that exposes a Movement for the properties we outlined in our DataStore.
In case you are not accustomed to flows, this is an efficient place to start out.
val todoItemFlow: Movement<TodoItems> = todoItemDataStore.knowledge
.catch { exception ->
if (exception is IOException) {
emit(TodoItems.getDefaultInstance())
} else {
throw exception
}
}
The code above exhibits how one can outline a Movement that collects knowledge from the Proto DataStore. A catch block was added in case an exception happens. You may place this logic within the class the place you outlined your DataStore and use it like so in your viewmodel:
val todoItemsFlow: LiveData<TodoItems> = todoItemsRepository.todoItemFlow.asLiveData()
Discover how we transformed our Movement to LiveData. We did this for 2 causes:
- Flows can keep lively whatever the exercise/fragment that makes use of them
- LiveData is one thing acquainted to many builders, and I wished to make this instance as approachable as attainable
To have the ability to do that, it is advisable to add the next dependency to your construct.gradle file:
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.6.2"
In your exercise/fragment class, you may observe this dwell knowledge like so:
myViewModel.todoItemFlow.observe(LocalLifecycleOwner.present) { todoItems ->
}
Why and When to Use DataStore
After every little thing we reviewed, it’s time to speak concerning the elephant within the room. Must you go forward and use DataStore (both Preferences or Proto) in your present or subsequent venture?
In my view, the reply must be Sure. Moreover the truth that Google is shifting away from SharedPreferences, DataStore presents loads of advantages that will help you focus in your software and never the persistence of your knowledge.
It’s protected to work together with the DataStore from the UI thread (because it strikes work to I/O robotically), and it forces you to make use of Movement (in the event you haven’t nonetheless) and revel in all the advantages inside. There’s additionally an choice to migrate simply from SharedPreferences to Preferences DataStore.
In case you are considering utilizing Room as an alternative of Proto DataStore, effectively that relies on your use case. If the quantity of knowledge you’ll save (or persist) is fairly small and received’t require partial updating, the Proto DataStore is the best way to go. You probably have a bigger knowledge set or one that could be complicated, you must go for utilizing Room as an alternative.
If you wish to see how all this code seems like in an software, you may see it right here:
If you wish to learn different articles I’ve written, you may see them right here:
Thanks for studying!
References: