首页 > 解决方案 > 如何在视图模型中从 DataStore 首选项中获取值,如 Flow

问题描述

我有一种情况可以通过 SharedPreferences 解决。但现在我正在迁移到 kotlin 和 DataStore。

我遇到了这个问题。

我有一个字符串值存储在共享首选项中,以及其他键值对。此 String 是一个 URL,在 Retrofit 调用的 baseUrl 参数中使用。

我的问题是,当我在 ViewModel 中运行 Fragment 时,检索值的正确方法是什么。

这是我的代码的一部分:

@Singleton
class PreferencesManager @Inject constructor(
    @ApplicationContext context: Context,
    anioDao: AnioDao
) {

   val baseUrlFlow = dataStore.data
        .catch { exception ->
            if (exception is IOException) {
                Log.e(TAG, "Error reading preferences: ", exception)
                emit(emptyPreferences())
            } else {
                throw exception
            }
        }
        .map {
            it[PreferencesKeys.BASER_URL] ?: "http://192.168.2.109:1337"
        }

}

然后在 ViewModel 类中

class EnsayosViewModel @ViewModelInject constructor(
    private val ensayoRepository: EnsayoRepository,
    private val anioRepository: AnioRepository,
    private val localidadRepository: LocalidadRepository,
    private val epocaRepository: EpocaRepository,
    private val preferencesManager: PreferencesManager,
    private val agrotrackerApi: AgrotrackerApi,
    @Assisted private val state: SavedStateHandle

) :
    ViewModel() {

...

//Base Url
val baseUrlFlow = preferencesManager.baseUrlFlow
private val _baseUrl = MutableLiveData<String>()
private fun getBaseUrl() {

    viewModelScope.launch {
        baseUrlFlow.flowOn(Dispatchers.IO).collect{
            _baseUrl.value = it
        }
    }
}

  ...

fun fetchEsayosFromAT() {

 //This is where I want to get value of the base_url key.

}

但这似乎很复杂,对于一个简单的任务......

我错过了什么?我真的迷路了。

此致

标签: androidkotlinandroid-jetpack-datastore

解决方案


获取共享首选项数据的一种方法是将 Flow 转换为 LiveData。它工作正常,但很可能会被 StateFlow/SharedFlow 取代,作为首选方法。

  1. 在返回 Flow 的 Preference 存储库中创建一个方法

    override fun getBaseUrlPreferencesFlow(): Flow<String> = context.dataStore.data
    .catch { exception ->
        if (exception is IOException) {
            Log.e(TAG, "Error reading preferences: ", exception)
            emit(emptyPreferences())
        } else {
            throw exception
        }
    }
    .map { pref ->
       it[PreferencesKeys.BASER_URL] ?: "http://192.168.2.109:1337"
    }
    
  2. 在您的 ViewModel 中初始化 LiveData,如下所示(您可以从 ViewModel 或 Fragment 访问它)

    val baseUrlLiveData: LiveData<String> = 
    yourInjectedRepository.getBaseUrlPreferencesFlow().asLiveData()
    
  3. (可选)在 ViewModel - 添加辅助方法来处理基本 url

    private fun processUrl(): String {
      viewModelScope.launch {
           // base url http://192.168.2.109:1337
           val url = baseUrlLiveData.value 
        }         
    }
    

推荐阅读