Issue
I want to store some preferences using DataStore. But the problem is that my application can have multiple users and therefor needs to store these preferences in separate files. I got a working example using only one user but I'm struggling to support multiple users.
Here is an example of my code:
class DataStorageRepository(private val context: Context, private val userRepository: UserRepository) {
private object PreferencesKeys {
val SETTING_ONE = intPreferencesKey("setting_one")
}
// retrieve datastore for currently logged in user.
private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = userRepository.currentRegistration().name)
val userPreferencesFlow: Flow<UserPreferences> = context.dataStore.data.map { preferences ->
val settingOne = preferences[PreferencesKeys.SETTING_ONE] ?: 0
UserPreferences(settingOne)
}
suspend fun storeSettingOne(settingOne: Int) {
context.dataStore.edit { preferences ->
preferences[PreferencesKeys.SETTING_ONE] = settingOne
}
}
data class UserPreferences(val lastUsedToAccountTab: Int)
}
I'm using Koin
and I tried unloading the DataStorageRepository
on logout and recreating it on login but the DataStore seems to stay alive until the app is killed and I get the following crash:
java.lang.IllegalStateException: There are multiple DataStores active for the same file: [...] You should either maintain your DataStore as a singleton or confirm that there is no two DataStore's active on the same file (by confirming that the scope is cancelled).
I also tried to use a CoroutineScope
and kill that when I log out, but after recreating the scope on login the DataStore doesn't seem to get recreated.
Does DataStore support a way to close the connection or to handle multiple files?
Solution
At the moment I was posting this question I found a solution to this problem. In order to solve my problem I needed to combine my previous two solutions. So on logout I unload the DataStorageRepository
and on login I reload it again. I also needed to create a CoroutineScope
that I cancel on logout.
My Module
val loggedInModule = module {
single { DataStorageRepository(get(), get()) }
}
I created a scope and passed it to the DataStore
var loggedInScope: CoroutineScope = CoroutineScope(Dispatchers.Default)
private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = userRepository.currentRegistration().name, scope = loggedInScope)
On Login
loggedInScope = CoroutineScope(Dispatchers.Default)
loadKoinModules(loggedInModule)
On Logout
loggedInScope.cancel()
unloadKoinModules(loggedInModule)
Answered By - Wirling
Answer Checked By - Terry (JavaFixing Volunteer)