9

我想使用 DataStore 存储一些首选项。但问题是我的应用程序可以有多个用户,因此需要将这些首选项存储在单独的文件中。我得到了一个仅使用一个用户的工作示例,但我正在努力支持多个用户。

这是我的代码示例:

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)
}

我正在使用Koin,我尝试卸载DataStorageRepository注销并在登录时重新创建它,但 DataStore 似乎一直存在,直到应用程序被杀死并且我得到以下崩溃:

java.lang.IllegalStateException:同一个文件有多个处于活动状态的 DataStore:[...] 您应该将 DataStore 保持为单例,或者确认同一个文件上没有两个处于活动状态的 DataStore(通过确认范围是取消)。

我还尝试CoroutineScope在注销时使用并杀死它,但是在登录时重新创建范围后,DataStore 似乎没有重新创建。

DataStore 是否支持关闭连接或处理多个文件的方法?

4

4 回答 4

6

将此行放入伴随对象 { }

private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "settingPrefs")

我的代码

class SettingPrefs(private val context: Context) {

    companion object {
        private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "settingPrefs")
        private val soundKey = booleanPreferencesKey("sound")
        private val vibrateKey = booleanPreferencesKey("vibrate")
    }

    val getSound: Flow<Boolean>
        get() = context.dataStore.data.map {
            it[soundKey] ?: true
        }

    suspend fun setSound(value: Boolean) {
        context.dataStore.edit { it[soundKey] = value }
    }

    val getVibration: Flow<Boolean>
        get() = context.dataStore.data.map {
            it[vibrateKey] ?: true
        }

    suspend fun setVibration(value: Boolean) {
        context.dataStore.edit { it[vibrateKey] = value }
    }
}
于 2021-04-28T17:27:38.863 回答
3

您可以为不同的用户使用不同的密钥或手动保留 DataStore 单例


例外情况:

java.lang.IllegalStateException:同一个文件有多个处于活动状态的 DataStore:[...] 您应该将 DataStore 保持为单例,或者确认同一个文件上没有两个处于活动状态的 DataStore(通过确认范围是取消)。

androidx.datastore:datastore-*:1.0.0-alpha07被释放。

把它放在你的 kotlin 文件的顶层,这样它就只有一个实例。

private val Context.dataStore by preferencesDataStore("settings")

class Xxx{

}

https://developer.android.com/jetpack/androidx/releases/datastore#1.0.0-alpha07

Context.createDataStore 扩展函数已被移除并替换为 globalDataStore 属性委托。在 kotlin 文件的顶层调用 globalDataStore 一次。例如:

val Context.myDataStore by dataStore(...) 

把它放在你的 kotlin 文件的顶层,这样它就只有一个实例。(I57215, b/173726702)

于 2021-04-16T14:04:01.780 回答
1

在我发布这个问题的那一刻,我找到了解决这个问题的方法。为了解决我的问题,我需要结合我之前的两个解决方案。所以在注销时我卸载DataStorageRepository并在登录时我再次重新加载它。我还需要创建一个CoroutineScope我在注销时取消的。

我的模块

val loggedInModule = module {
    single { DataStorageRepository(get(), get()) }
}

我创建了一个范围并将其传递给 DataStore

var loggedInScope: CoroutineScope = CoroutineScope(Dispatchers.Default)

private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = userRepository.currentRegistration().name, scope = loggedInScope)

登录时

loggedInScope = CoroutineScope(Dispatchers.Default)
loadKoinModules(loggedInModule)

注销时

loggedInScope.cancel()
unloadKoinModules(loggedInModule)
于 2021-03-17T09:08:59.627 回答
0

只需将您的声明数据存储区从您的 DataStorageRepository 类中取出

private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name="settings")

class DataStorageRepository(context: Context) {

   private var appContext = context.applicationContext

   val mData: Flow<String?> = appContext.dataStore.data.map { preferences ->
          preferences[YOUR_KEY]
   }

   suspend fun insertData(value: String) {
        appContext.dataStore.edit { preferences ->
             preferences[YOUR_KEY] = authToken
        }
   }

   companion object {
        private val KEY = stringPreferencesKey("data")
   }
}
于 2021-12-05T10:15:14.787 回答