Search code examples
kotlinandroid-jetpack-composedatastore

How to load instantly data from data store?


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.


Solution

  • 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.