TLDR: I've been fighting most of the day today with DataStore
, more specifically why most suspend methods seem to just hang forever and only map {}.first
worked for me to get the Preferences
object.
I'm writing a small Android app with very lightweight use of local storage:
What finally worked:
val preferences =
context.transliterationStatesDataStore.data.firstOrNull() ?: return
val preferences =
context.dataStore.data.map { preferences -> preferences }
.first()
What I've tried before:
val preferences =
context.dataStore.data.map { preferences -> preferences }
.lastOrNull() ?: return
val preferences =
context.dataStore.data.lastOrNull() ?: return
Log.d("debug", context.dataStore.data.count().toString())
I'm confused why:
.count()
didn't work (suspended forever).lastOrNull()
didn't work (suspended forever)Preferences
from disk.There is a related question here but it didn't receive any answers beyond more data points from the author.
A Flow from DataStore is infinite because it monitors the storage in perpetuity so it can emit every time the value changes. Since it's infinite, functions that collect the flow until its final value to get its total count
(infinity) or last
value (which never comes) will hang forever.
Flows are cold. When you call first()
, then the flow queries the data store to get the current value to emit for collection. It will be the most up-to-date value. first()
is the correct way to get the latest value only. If you want to continually react to the latest value as new values are posted, then you can use collect { }
instead of first()
.
You will find that most Flows are infinite if they monitor something like storage or a database. For example, Flows returned by Room database functions are all infinite, just like the ones from DataStore.