Please help me figure out how to instantly load a stored value from DataStore As I understand when I have try to get Data after reloading app the first seconds the value will be initial(false) and only then will become true (if true was stored).
Code snippet's:
class StoreManager(private val context: Context) {
companion object {
private val Context.dataStore: DataStore<Preferences> by preferencesDataStore("store_sample")
val BOOLEAN_KEY = booleanPreferencesKey("BOOLEAN_KEY")
}
suspend fun saveBoolean(value: Boolean) {
context.dataStore.edit {
it[BOOLEAN_KEY] = value
}
}
val booleanData: Flow<Boolean> = context.dataStore.data.map {
it[BOOLEAN_KEY] ?: false
}}
And incomplite @Composable fun
@Composable
fun GpsScreen() {
val storeManager = StoreManager(LocalContext.current)
val coroutineScope = rememberCoroutineScope()
val newData = storeManager.booleanData.collectAsState(initial = false)
Button(
onClick = {
// DataStore
coroutineScope.launch {
storeManager.saveBoolean(isDecimalPosition)
}
},
modifier = Modifier
.fillMaxWidth()
.padding(PADDING_BIG)
.align(Alignment.CenterHorizontally)
) {
Text(
textAlign = TextAlign.Center,
text = "TXT"
)
}}
The code is not complete but works fine. The only thing is not clear what to do to instantly load the desired value.
CodePudding user response:
In your DataStore, you can do this:
val readBoolean: Flow<Boolean> = dataStore.data
.catch { exception ->
if (exception is IOException) {
println(exception.message.toString())
emit(emptyPreferences())
} else {
throw exception
}
}
.map { preference ->
val userBoolean: Boolean =
preference[PreferenceKeys.booleanPreferencesKey] ?: false
userBoolean
}
suspend fun saveBoolean(boolean: Boolean) {
dataStore.edit { preference ->
preference[PreferenceKeys.booleanPreferencesKey] = boolean
}
}
You can put it in your viewModel as liveData like this:
val readBoolean= dataStore.readBoolean.asLiveData()
fun saveBoolean(myBoolean: Boolean) = viewModelScope.launch {
dataStore.saveBoolean(myBoolean)
}
CodePudding user response:
You load datastore "instantly" i.e. synchronously by blocking the thread using runBlocking
.
class StoreManager(private val context: Context) {
companion object {
private val Context.dataStore: DataStore<Preferences> by preferencesDataStore("store_sample")
val BOOLEAN_KEY = booleanPreferencesKey("BOOLEAN_KEY")
}
suspend fun saveBoolean(value: Boolean) {
context.dataStore.edit {
it[BOOLEAN_KEY] = value
}
}
val booleanData = MutableStateFlow(false)
// Call this whenever you want to load booleanData
// You could make the booleanData to listen to change by collecting the flow after calling loadBoolean()
fun loadBoolean() {
runBlocking {
booleanData.value = context.dataStore.data.map {
it[BOOLEAN_KEY] ?: false
}.first()
}
}
}
@Composable
fun GpsScreen() {
val storeManager = remember { StoreManager(LocalContext.current) }
LaunchedEffect(Unit) {
storeManager.loadBoolean()
}
val coroutineScope = rememberCoroutineScope()
val newData = storeManager.booleanData
Button(
onClick = {
// DataStore
coroutineScope.launch {
storeManager.saveBoolean(isDecimalPosition)
}
},
modifier = Modifier
.fillMaxWidth()
.padding(PADDING_BIG)
.align(Alignment.CenterHorizontally)
) {
Text(
textAlign = TextAlign.Center,
text = "TXT"
)
}
}
Disclaimer: It has a chance to block your UI thread long enough (if the data is relatively huge or something) and cause ANR.
On the other hand, you could provide a loading screen for the user when you are loading the data from the datastore.