![](/img/trans.png)
[英]How to get a value from DataStore preferences, as Flow, within viewmodel
[英]How can I convert DataStore preferences' Flow to StateFlow inside a viewModel in Jetpack Compose
我正在嘗試使用 DataStore 參考為我的應用程序實現“設置”屏幕。 基本上,根據偏好創建一個 url,因此 WebView 可以稍后加載它。 數據已正確保存,設置屏幕中的 UI 會在首選項更改時更新值。
問題是我發現,在嘗試加載更新的 url 時,不會立即讀取首選項(WebView 在更新后加載以前的 url 值)。 所以我的問題是如何將其轉換為該類型以便實時讀取首選項?
以下是一些代碼片段:
用戶偏好數據 class
data class UserPreferences(
val conexionSegura: Boolean,
val servidor: String,
val puerto: String,
val pagina: String,
val parametros: String,
val empresa: String,
val inicioDirecto: Boolean,
val usuario: String,
val password: String,
val url: String
)
DataStore 存儲庫實現 getPreferences()
class DataStoreRepositoryImpl @Inject constructor(
private val dataStore: DataStore<Preferences>
) : DataStoreRepository {
override suspend fun getPreferences() =
dataStore.data
.map { preferences ->
UserPreferences(
conexionSegura = preferences[PreferencesKeys.CONEXION_SEGURA] ?: false,
servidor = preferences[PreferencesKeys.SERVIDOR] ?: "",
puerto = preferences[PreferencesKeys.PUERTO] ?: "",
pagina = preferences[PreferencesKeys.PAGINA] ?: "",
parametros = preferences[PreferencesKeys.PARAMETROS] ?: "",
empresa = preferences[PreferencesKeys.EMPRESA] ?: "",
inicioDirecto = preferences[PreferencesKeys.INICIO_DIRECTO] ?: false,
usuario = preferences[PreferencesKeys.USUARIO] ?: "",
password = preferences[PreferencesKeys.PASSWORD] ?: "",
url = preferences[PreferencesKeys.URL] ?: CONTENT_URL
)
}
...
...
視圖模型 readPreferences()
private val _state = mutableStateOf(SettingsState())
val state: State<SettingsState> = _state
init {
readPreferences()
updateUrl()
}
private fun readPreferences() {
viewModelScope.launch {
dataStoreRepositoryImpl.getPreferences().collect {
_state.value = state.value.copy(
conexionSegura = it.conexionSegura,
servidor = it.servidor,
puerto = it.puerto,
pagina = it.pagina,
parametros = it.parametros,
empresa = it.empresa,
inicioDirecto = it.inicioDirecto,
usuario = it.usuario,
password = it.password
)
}
}
}
...
...
在調查和閱讀了一些內容之后,我意識到 DataStore 發出流,而不是 stateFlows,這在 compose 中是需要的。 我考慮過刪除 UserPreferences class,一次只讀取一個偏好,將其收集為屏幕可組合項中的狀態。 但是,我認為代碼會更清晰,因為我不這樣做 :) 我真的很喜歡使用單獨的 class 來保存首選項值的想法
當您想要將 ViewModel 中的Flow
轉換為StateFlow
以在視圖中使用時,正確的方法是使用stateIn()方法。
假設你有以下 class 和接口:
class SettingsState()
sealed interface MyDatastore {
fun getPreferences(): Flow<SettingsState>
}
在您的 viewModel 中,創建一個將使用 datatStore.getPreferences 方法的 val,並使用 stateIn 將流轉換為 stateFlow
class MyViewModel(
private val dataStore: MyDatastore
) : ViewModel() {
val state: StateFlow<SettingsState> = dataStore
.getPreferences()
.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5_000),
initialValue = SettingsState()
)
}
要開始獲取首選項,您只需將 stateFlow 收集為 state:
@Composable
fun MyComposable(
myViewModel: MyViewModel = hiltViewModel()
) {
val state = myViewModel.state.collectAsState()
//...
}
如您所見,您不需要在ViewModel
中使用init
。 像 90% 的時間一樣,不需要使用init
。 ViewModel 變得更易於測試,因為您不需要模擬init
塊中的所有內容。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.