Reputation: 3036
I am trying to introduce preferences DataStore in my Android Compose app and several tutorials suggest the use of Conext for keeping the reference to the DataStore instance. E.g. https://betterprogramming.pub/using-jetpack-preferences-datastore-more-effectively-414e1126cff7 and https://towardsdev.com/using-android-jetpack-datastore-with-jetpack-compose-6184338cf9c0 are such tutorials.
While it is possible to use Context for this, the Context is accessible from the Composables only and not from the ViewModels and repositories which are expected to be the most heavy users of DataStore. E.g. ViewModels can have functions that execute write functions of the DataStore. Repositories can read the saved URL from the DataStore.
So - Context is not the appropriate object to keep references to that DataStore, but which object is appropriate? Maybe AppContainer?
DataStore is expected to be application wide singleton. Maybe preferencesDataStore
is already guaranteeing this?
I.e. maybe I can call
myLocalVariable: DataStore<Preferences> by preferencesDataStore(name = "my_app_configuration")
in each of my ViewModel or repository and then I can use myLocalVariable
in those modules freely and the perferencesDataStore
guarntees that there is only one DataStore instance for the entire application?
Upvotes: 0
Views: 3788
Reputation: 1038
My suggestion would be to use Hilt to inject code into viewModel Here is a example.
@Module
@InstallIn(SingletonComponent::class)
object Singleton {
/**
* Provides the Singleton Implementation of Preferences DataStore.
*/
@Provides
@Singleton
fun preferences(@ApplicationContext context: Context) = Preferences(context)
}
Here the Preferences is a wraaper around DataStore.
Now you inject the instance of Preference into the viewModel easily.
Here I have created a lib to make the integration with compose easily. here is the dependency from jitpack the io implementation 'com.github.prime-zs:support:Tag'
Upvotes: 1
Reputation: 66506
Using dependency inversion and abstraction you can keep Android code out of your repository classes as they should and using dependency injection you can pass Context to implementation, assuming Dagger is used you can bind your interface to implementation using @Binds
annotation
create an Interface for write/read operations
interface MyDataStore {
fun read()
fun write()
}
an implementation that takes Context as argument
class DataStoreImpl(context:Context):MyDataStore {
// Implementation
}
If you define your repositories or ViewModels as
class Repository(myDataStore: MyDataStore)
you will be able to remove coupling to context or DataStore in your classes. This way if google decides to introduce another class for storage in the future you can easily replace it with existing one or can implement multiple implementation versions and change to required one using polymorphism
Upvotes: 2