Estaba tratando de proporcionar un DataStore<Preferences>
común para que el mismo archivo de preferencias pudiera usarse en varios lugares, pero recibí el útil mensaje de error:
No se puede encontrar el símbolo: DaggerMyApplication_HiltComponents_SingletonC.builder()
@Module @InstallIn(ApplicationComponent::class) object DataStoreModule { @Provides fun provideDataStore(@ApplicationContext context: Context): DataStore<Preferences> = context.createDataStore("settings") }
Sin embargo, puedo hacer lo siguiente y usarlo dentro de un constructor @Inject
.
@Singleton class DataStoreProvider @Inject constructor(@ApplicationContext context: Context) { val dataStore: DataStore<Preferences> = context.createDataStore("settings") }
Supongo que la extensión createDataStore
está haciendo algo que a Hilt no le gusta, pero agradecería una explicación de lo que está pasando incluso si el problema no tiene solución.
Como menciona Dr.jacky, ahora se recomienda crear un administrador, pero aún puede usar PreferenceDataStoreFactory
y crear Preferences DataStore singleton:
@Provides @Singleton fun providePreferencesDataStore(@ApplicationContext appContext: Context): DataStore<Preferences> = PreferenceDataStoreFactory.create( produceFile = { appContext.preferencesDataStoreFile(PREFERENCES_STORE_NAME) } )
Esto funcionó para mí:
@Provides @Singleton fun dataStore(@ApplicationContext appContext: Context): DataStore<Preferences> = appContext.createDataStore("settings")
La idea es poner a @Singleton
detrás del método del proveedor.
Actualización el 9 de febrero de 2021:
De preferencia, crear un administrador y disponer que:
class DataStoreManager(appContext: Context) { private val settingsDataStore = appContext.createDataStore("settings") suspend fun setThemeMode(mode: Int) { settingsDataStore.edit { settings -> settings[Settings.NIGHT_MODE] = mode } } val themeMode: Flow<Int> = settingsDataStore.data.map { preferences -> preferences[Settings.NIGHT_MODE] ?: AppCompatDelegate.MODE_NIGHT_UNSPECIFIED } }
@InstallIn(SingletonComponent::class) @Module class AppModule { @Provides @Singleton fun dataStoreManager(@ApplicationContext appContext: Context): DataStoreManager = DataStoreManager(appContext)
Actualización el 20 de marzo de 2021:
Versión 1.0.0-alpha07
private val Context.dataStore by preferencesDataStore("settings") class DataStoreManager(appContext: Context) { private val settingsDataStore = appContext.dataStore suspend fun setThemeMode(mode: Int) { settingsDataStore.edit { settings -> settings[Settings.NIGHT_MODE] = mode } } val themeMode: Flow<Int> = settingsDataStore.data.map { preferences -> preferences[Settings.NIGHT_MODE] ?: AppCompatDelegate.MODE_NIGHT_UNSPECIFIED } }
Actualización del 1 de mayo de 2021: @Florian tiene toda la razón, lo había olvidado.
Eliminar el proveedor de dataStoreManager
. Luego,
private val Context.dataStore by preferencesDataStore("settings") @Singleton //You can ignore this annotation as return `datastore` from `preferencesDataStore` is singletone class DataStoreManager @Inject constructor(@ApplicationContext appContext: Context) { private val settingsDataStore = appContext.dataStore suspend fun setThemeMode(mode: Int) { settingsDataStore.edit { settings -> settings[Settings.NIGHT_MODE] = mode } } val themeMode: Flow<Int> = settingsDataStore.data.map { preferences -> preferences[Settings.NIGHT_MODE] ?: AppCompatDelegate.MODE_NIGHT_UNSPECIFIED } }
DataStore<Preferences>
con Hilt de la siguiente manera.
MóduloPersistencia.kt
@Module @InstallIn(SingletonComponent::class) object PersistenceModule { @Provides @Singleton fun provideDataStoreManager(@ApplicationContext context: Context): DataStoreManager { return DataStoreManager(context) } }
DataStoreManager.kt
class DataStoreManager @Inject constructor(@ApplicationContext private val context: Context) { private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(STORE_NAME) private suspend fun <T> DataStore<Preferences>.getFromLocalStorage( PreferencesKey: Preferences.Key<T>, func: T.() -> Unit) { data.catch { if (it is IOException) { emit(emptyPreferences()) } else { throw it } }.map { it[PreferencesKey] }.collect { it?.let { func.invoke(it as T) } } } suspend fun <T> storeValue(key: Preferences.Key<T>, value: T) { context.dataStore.edit { it[key] = value } } suspend fun <T> readValue(key: Preferences.Key<T>, responseFunc: T.() -> Unit) { context.dataStore.getFromLocalStorage(key) { responseFunc.invoke(this) } } }
VerModelo.kt
@HiltViewModel class HomeViewModel @Inject constructor( private val dataStore: DataStoreManager ) : LiveCoroutinesViewModel() { fun readNextReviewTime() { viewModelScope.launch { dataStore.readValue(nextReviewTime) { // Here you can do something with value. } } } }
Actualizar
@HiltViewModel class TranslateViewModel @Inject constructor( definitionRepository: DefinitionRepository, translateRepository: TranslateRepository, val dataStoreManager: DataStoreManager ) : LiveCoroutinesViewModel() { init { readValueInViewModelScope(sourceLanguage, "ta") { // use value here } readValueInViewModelScope(targetLanguage, "si") { // use value here } } private fun <T> readValueInViewModelScope(key: Preferences.Key<T>, defaultValue: T, onCompleted: T.() -> Unit) { viewModelScope.launch { dataStoreManager.readValue(key) { if (this == null) { storeValueInViewModelScope(key, defaultValue) } else { onCompleted.invoke(this) } } } } fun <T> storeValueInViewModelScope(key: Preferences.Key<T>, value: T) { viewModelScope.launch { dataStoreManager.storeValue(key, value) } } }