7

Am I missing something or is it not possible to attach a listener to the new Android Jetpack Preference Datastore? I thought the whole point of using Flow is that we can call flow.toLiveData() on the Preference Datastore and observe changes to the value changes.

Here is how I am getting a Flow from the Datastore.

 val taxRatePreferenceFlow: Flow<TaxRate> = dataStore.data
        .catch { exception ->
            if (exception is IOException){
                emit(emptyPreferences())
            } else {
                throw exception
            }
        }.map { preferences ->
            val name = preferences[PreferencesKeys.TAX_LABEL] ?: "Tax"
            val rate = preferences[PreferencesKeys.TAX_RATE] ?: Constants.DEFAULT_TAX_RATE.toFloat()
            val type = TaxType.valueOf(preferences[PreferencesKeys.TAX_TYPE] ?: TaxType.ON_ITEMS.name)
            TaxRate(name, rate, type)
        }

I was hoping to convert the Flow to a LiveData like so in the ViewModel and listen for changes until the observers are removed.

totalAmountLiveData.addSource(taxRateFlow.asLiveData()){ taxtRate ->
            taxtRate?.let {
                updateTaxAmount(it)
            }
        }

However this observer only emits the saved value and does not update as the values are updated. Exiting and re-entering the screen shows the updated value.

And here is how I update each value in the DataStore

 suspend fun updateTaxLabel(newTaxLabel: String){
        dataStore.edit { preferences ->
            preferences[PreferencesKeys.TAX_LABEL] = newTaxLabel
        }
    }

What am I missing, should I be using collect instead of map? If yes, can someone show me an example of how to use Flow collect in this context.

Val Okafor
  • 3,371
  • 13
  • 47
  • 72

1 Answers1

3

You can directly observe the flow as a liveData, no need to add it as source for another live data.

Your code would change from

totalAmountLiveData.addSource(taxRateFlow.asLiveData()){ taxtRate ->
        taxtRate?.let {
            updateTaxAmount(it)
        }
    }

to

taxRateFlow.asLiveData().observe(this */ lifeCycleOwner */) {
            updateTaxAmount(it)
}

In this case you can directly see your data changing the datastore and perform the functions accordingly.

Priyansh Kedia
  • 171
  • 1
  • 6
  • facing the problem here. The issue is that asLiveData() calls collect(), so the Flow is terminated and you won't get further updates... – Droidman Apr 30 '21 at 11:18
  • @Droidman so is there a way to observe for changes to the preferences? – KenIchi Jul 02 '23 at 11:51
  • @KenIchi I haven't looked into that further because the migration to data store is all the way down on the priority list, so I can't provide any updates right now, sorry – Droidman Jul 03 '23 at 12:32
  • @Droidman Thank you FYI, I was looking into several other similar questions, and they suggest calling asLiveData() but I suspect they don't get updated on-the-fly. Looking for other confirmations here. – KenIchi Jul 04 '23 at 11:01
  • 2
    I've confirmed `preferencesDataStore` can be subscribed to and get updated on-the-fly, you can observe it for further changes. Check this gist: https://gist.github.com/KentVu/a65baf115adc0fb91a13d14bee7054f9 – KenIchi Jul 05 '23 at 04:01
  • 1
    @KenIchi the code seems correct, but the issue here is because of asLiveData(). The [Android Docs](https://developer.android.com/reference/kotlin/androidx/lifecycle/package-summary#(kotlinx.coroutines.flow.Flow).asLiveData(kotlin.coroutines.CoroutineContext,java.time.Duration)) mention that on successful completion of Flow, it will not be recollected (in case of asLiveData). [DataStore](https://developer.android.com/topic/libraries/architecture/datastore) was indeed built for asynchronous and on-the-fly updates. Thanks – Priyansh Kedia Jul 06 '23 at 21:09
  • @Droidman, I could not find an alternative to asLiveData without terminating the flow after once, but I would suggest not using LiveData (in place of Flows) but instead using [Flows](https://developer.android.com/kotlin/flow) itself as the new releases have a lot of helpful APIs to manage your data. Thanks – Priyansh Kedia Jul 06 '23 at 21:13