Reputation: 95
My DataStore keeps returning null even though I've set a default value on the preferences manager using the elvis operator. Also, my edit function to set a preference on a key-value pair isn't being called so I'm not even sure my datastore is properly setup in general. I'm pretty sure the class is properly injected though, because I can see it as a variable while using breakpoints.
Basically val countryCode = viewModel.countrySettings.value
on the ViewModel always returns null
PreferencesManager class
const val TAG = "PreferencesManager"
const val DEFAULT_COUNTRY_PREFERENCE = "us"
const val DEFAULT_CATEGORY_PREFERENCE = "general"
private val Context.dataStore by preferencesDataStore(name = PREFERENCES_NAME)
@Singleton
class PreferencesManager @Inject constructor(@ApplicationContext appContext: Context) {
private val preferencesDataStore = appContext.dataStore
//Pairs are separated but I'll create an appropriate data class later.
val countrySettings = preferencesDataStore.data
.catch { exception ->
if (exception is IOException) {
Log.e(TAG, "Error while trying to read user preferences", exception)
emit(emptyPreferences())
} else {
throw exception
}
}
.map { preference ->
val country = preference[PreferenceKeys.COUNTRY] ?: DEFAULT_COUNTRY_PREFERENCE
country
}
val categorySettings = preferencesDataStore.data
.catch { exception ->
if (exception is IOException) {
Log.e(TAG, "Error while trying to read user preferences", exception)
emit(emptyPreferences())
} else {
throw exception
}
}
.map { preferences ->
val category = preferences[PreferenceKeys.CATEGORY] ?: DEFAULT_CATEGORY_PREFERENCE
category
}
suspend fun setCountryPreference(country: String) {
preferencesDataStore.edit { preference ->
preference[PreferenceKeys.COUNTRY] = country
}
}
suspend fun setCategoryPreference(category: String) {
preferencesDataStore.edit { preference ->
preference[PreferenceKeys.CATEGORY] = category
}
}
private object PreferenceKeys {
val COUNTRY = stringPreferencesKey("country")
val CATEGORY = stringPreferencesKey("category")
}
}
ViewModel
class MainViewModel @Inject constructor(
private val repository: Repository,
private val preferencesManager: PreferencesManager
): ViewModel() {
val countrySettings = preferencesManager.countrySettings.asLiveData()
val categorySettings = preferencesManager.categorySettings.asLiveData()
/* .... */
fun setCountryPreference(country: String) {
viewModelScope.launch {
preferencesManager.setCountryPreference(country)
}
}
fun setCategoryPreference(category: String) {
viewModelScope.launch {
preferencesManager.setCategoryPreference(category)
}
}
}
Fragment
val viewModel: MainViewModel by activityViewModels()
private var _binding: FragmentSettingsCountryScreenBinding? = null
private val binding get() = _binding!!
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
_binding = FragmentSettingsCountryScreenBinding.bind(view)
//Using breakpoints I've noticed this function isn't even called on the preferences manager to set the value, which is weird
viewModel.setCountryPreference("us")
val countryCode = viewModel.countrySettings.value
binding.radiogroup.check(adaptPreferenceFromDataStore(countryCode!!))
binding.radiogroup.setOnCheckedChangeListener { _, checkedId ->
viewModel.setCountryPreference(adaptPreferenceToDataStore(checkedId))
}
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}
Upvotes: 2
Views: 2930
Reputation: 95
Yes, ianhanniballake is correct, it was a newbie mistake - I completely forgot I had to observe the livedata value and just then set the UI parameters. I was trying to set the preferences based on the value of a few switches (and vice-versa). Here's the proper function for setting it up:
fun setupSwitches() {
viewModel.countrySettings.observe(viewLifecycleOwner, { preference ->
binding.radioGroup.check(adaptPreferenceFromDataStore(preference))
})
binding.radioGroup.setOnCheckedChangeListener { _, checkedId ->
viewModel.setCountryPreference(adaptPreferenceToDataStore(checkedId))
}
}
Then called setupSwitches()
on onViewCreated
.
Upvotes: 2