DEV Community

Cover image for If use Jetpack compose don't use Shared Preference
Gianluca La Manna
Gianluca La Manna

Posted on

If use Jetpack compose don't use Shared Preference

I've recently been working with Jetpack Compose in a mobile project. If you don't know what it is, I suggest you watch this.

In all the apps I've developed, it is always required to save some information in the local memory, such as the user's preferences or username.

The Shared Preference seems to be the most correct choice in this case.
But if we use a Jetpack compose, we must not use them.

Use a DataStore ✨

In order to use DataStore correctly always keep in mind the following rules:

  1. Never create more than one instance of DataStore for a given file in the same process.

  2. The generic type of the DataStore must be immutable.

  3. Never mix usages of SingleProcessDataStore and MultiProcessDataStore for the same file.

More detail here

Differences between Shared Preference and DataStore

Following the main differences

Image description

If you interessed at Proto DataStore read this

Implementation 🧑🏻‍💻

First of all, add the following to your Gradle file



    implementation "androidx.datastore:datastore-preferences:1.0.0"


Enter fullscreen mode Exit fullscreen mode

Let’s create an instance of a data store for storing and fetching data



class StoreData(private val context: Context) {

    companion object {
        private val Context.dataStore: DataStore<Preferences> by preferencesDataStore("storeData")
        val USERNAME = stringPreferencesKey("store_Data")

    }
...
}


Enter fullscreen mode Exit fullscreen mode

Create the methods fo read and write data into DataStore




val getData: Flow<String?> = context.dataStore.data
   .map { preferences ->
         preferences[USERNAME] ?: ""
     }

suspend fun saveData(name: String) {
    context.dataStore.edit { preferences ->
        preferences[USERNAME] = name
    }
}


Enter fullscreen mode Exit fullscreen mode

Remember: DataStore use Async API, so if you want call saveData use a kotlin's coroutine.



val scope = rememberCoroutineScope()

scope.launch {
    dataStore.saveData(username.value)
}


Enter fullscreen mode Exit fullscreen mode

Use this function if you want check if the key is in store



   fun isKeyStored(key: Preferences.Key<String>): Flow<Boolean>  =
        context.dataStore.data.map {
                preference -> preference.contains(key)
        }


Enter fullscreen mode Exit fullscreen mode

Sounds cool. But if you want save an object? A list for example? We need serialize the object.

I used the Gson library.

Add to your Gradle file



    implementation 'com.google.code.gson:gson:2.8.7'


Enter fullscreen mode Exit fullscreen mode

then create the instance of Gson and the methods for read and write



 private val gson: Gson = Gson()

 suspend fun saveData(name: List<DataObject>) {
        context.dataStore.edit { preferences ->
            val jsonString = gson.toJson(name)
            preferences[OBJECT] = jsonString
        }
    }

    val getData: Flow<List<DataObject>> = context.dataStore.data
        .map { preferences ->
            val jsonString = preferences[OBJECT] ?: ""
            gson.fromJson(jsonString, Array<DataObject>::class.java).toList()
        }


Enter fullscreen mode Exit fullscreen mode

So if you want check if data is in store and get object, use this



if(dataStore.isKeyStored(stringPreferencesKey("store_Data")).collectAsState(initial = false).value) {
        dataStore.getData.collectAsState(initial = listOf(DataObject(x, y))).value.let {
            myViewModel.setDataMethod(it)
        }
    }


Enter fullscreen mode Exit fullscreen mode

and that's all.

See ya 👋🏻
Thank you for reading ✨

Top comments (2)

Collapse
 
hamid842 profile image
Hamid Mohamadi

Thanks for this article. I'm wondering how to use this into Jetpack compose?
I mean what can I pass to StoreData class as context/

Collapse
 
kumaraish profile image
kumaraish

val context = LocalContext.current