If use Jetpack compose don't use Shared Preference
Tags: android, kotlin, mobile, tutorial
Published: 2023-03-06 21:31:03

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](https://medium.com/gradeup/jetpack-compose-everything-you-need-to-know-to-get-started-2db13d248b0a).

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](https://developer.android.com/topic/libraries/architecture/datastore)

## Differences between Shared Preference and DataStore

Following the main differences

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/udw2tyu1z8wrw5lf947y.jpg)

If you interessed at Proto DataStore read [this](https://developer.android.com/topic/libraries/architecture/datastore#proto-datastore-dependencies)

## Implementation 🧑🏻‍💻

First of all, add the following to your Gradle file

```gradle
    implementation "androidx.datastore:datastore-preferences:1.0.0"
```
Let’s create an instance of a data store for storing and fetching data

```kotlin
class StoreData(private val context: Context) {

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

    }
...
}
```

Create the methods fo read and write data into DataStore

```kotlin

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

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

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

```kotlin
val scope = rememberCoroutineScope()

scope.launch {
    dataStore.saveData(username.value)
}
```
 Use this function if you want check if the key is in store

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

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

```gradle
    implementation 'com.google.code.gson:gson:2.8.7'
```
then create the instance of Gson and the methods for read and write

```kotlin
 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()
        }
```
So if you want check if data is in store and get object, use this

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

and that's all.

See ya 👋🏻
Thank you for reading ✨