Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

440
Vistas
Provide preferences datastore with Hilt

I was trying to provide a common DataStore<Preferences> so that the same preference file could be used in multiple places but I got the helpful error message:

Cannot find symbol: DaggerMyApplication_HiltComponents_SingletonC.builder()

@Module
@InstallIn(ApplicationComponent::class)
object DataStoreModule {
    
    @Provides
    fun provideDataStore(@ApplicationContext context: Context): DataStore<Preferences> = context.createDataStore("settings")
}

I can however do the following and use it within an @Inject constructor.

@Singleton
class DataStoreProvider @Inject constructor(@ApplicationContext context: Context) {

    val dataStore: DataStore<Preferences> = context.createDataStore("settings")
}

I assume that the extension createDataStore is doing something that Hilt does not like but I'd appreciate an explanation of what is going on even if the problem is not solvable.

over 4 years ago · Hanz Gallego
3 Respuestas
Responde la pregunta

0

As Dr.jacky mention, create a manager is now recommended way, but you can still use PreferenceDataStoreFactory and create Preferences DataStore singleton:

@Provides
@Singleton
fun providePreferencesDataStore(@ApplicationContext appContext: Context): DataStore<Preferences> =
    PreferenceDataStoreFactory.create(
        produceFile = {
            appContext.preferencesDataStoreFile(PREFERENCES_STORE_NAME)
        }
    )
over 4 years ago · Hanz Gallego Denunciar

0

This worked for me:

    @Provides
    @Singleton
    fun dataStore(@ApplicationContext appContext: Context): DataStore<Preferences> =
        appContext.createDataStore("settings")

The idea is putting @Singleton behind the provider method.


Update on Feb 9, 2021:
Preferably, create a manager and provide that:

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
    }

}

AppModule:

@InstallIn(SingletonComponent::class)
@Module
class AppModule {
    @Provides
    @Singleton
    fun dataStoreManager(@ApplicationContext appContext: Context): DataStoreManager =
        DataStoreManager(appContext)

Update on March 20, 2021:
Version 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
    }
}

Update on May 1, 2021: @Florian is totally right, I had forgotten that.

Remove dataStoreManager provider. Then,

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
    }

}
over 4 years ago · Hanz Gallego Denunciar

0

I used DataStore<Preferences> with Hilt as following.

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

ViewModel.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.
            }
        }
    }
}

Update

@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)
        }
    }
}
over 4 years ago · Hanz Gallego Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Asistente virtual