App data and files
Published: 2023-03-07 14:20:56

In this post, I discuss, how to preserve user data either as files on the device, in key-value pairs, in a database, or with other data types, and share data between other apps and devices. 

Android uses a file system that's similar to disk-based file systems on other platforms. The system provides several options for you to save your app data.

01. App-specific storage : Store files that are for your app's use only. Use the directories within internal storage to save sensitive information that other apps shouldn't access.

02. Shared storage: Store files that your app intends to share with other apps, including media, documents, and other files.

03. Preferences*: Store private, primitive data in key-value pairs.

04. Databases*: Store structured data in a private database using the Room library.

## App-specific storage

https://developer.android.com/training/data-storage/app-specific#kotlin

Store a file:

```kotlin
val filename = "myfile"
val fileContents = "Hello world!"
context.openFileOutput(filename, Context.MODE_PRIVATE).use {
        it.write(fileContents.toByteArray())
}
```

Access a file:

```kotlin
context.openFileInput(filename).bufferedReader().useLines { lines ->
    lines.fold("") { some, text ->
        "$some\n$text"
    }
}
```

## Preferences

01. SharedPreference

It stores data using key-value pairs. It can store primitive data type → boolean, float, double, int, String.

For use storing - user details, user setting, last score, location catching, multiple choice question.

Store a data:

```kotlin
private fun onSplashFinished(){
    val sharedPref = requireActivity().getSharedPreferences("onBoarding", Context.MODE_PRIVATE)
    val editor = sharedPref.edit()
        //..
    editor.putInt("age", 23)
    editor.putBoolean("Finished", true)
    editor.apply()
    //.. or better use
    editor.apply{
       putInt("age", 23)
       putBoolean("Finished", true)
       apply()
    }
}
```

Access a data:

```kotlin
private fun onBoardingFinished(): Boolean {
    val sharedPref = requireActivity().getSharedPreferences("onBoarding",Context.MODE_PRIVATE)
    val value = sharedPref.getBoolean("Finished", false)
    return value 
}
```

data a remove:

```kotlin
val sharedPref = this.getSharedPreferences("onBoarding", Context.MODE_PRIVATE)
sharedPref.edit().remove("splashFinished").apply()
```
- https://developer.android.com/training/data-storage/shared-preferences

02. DataStore 

DataStore is a new and improved data storage solution intended to replace SharedPreferences. Built on Kotlin and Flow coroutines Android  provided by Jetpack library. DataStore advantages are like type safety, asynchronous APIs, and support for observing data changes.

Two kind of versions of data store you can use. The one is "Preferences datastore". Other kind is "proto datastore". So there are very similar but proto datastore is also typesafe,  preferences datastore are not.

(i) Preferences datastore

It is well-suited for scenarios where you need to store a small amount of data and want to avoid the complexities of working with SharedPreferences.

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

**Creating a Preferences DataStore**

```kotlin
val dataStore: DataStore<Preferences> = context.createDataStore(name = "my_preferences")
```
**Storing Data**
```kotlin
// Writing data
dataStore.edit { preferences ->
    preferences[booleanPreferencesKey("isFirstLaunch")] = true
    preferences[intPreferencesKey("userScore")] = 100
}
// Writing data
suspend fun setExampleValue(newValue: String) {
    dataStore.edit { preferences ->
        preferences[EXAMPLE_KEY] = newValue
    }
}
```
**Retrieving Data**
```kotlin
val isFirstLaunchFlow: Flow<Boolean> = dataStore.data.map { preferences ->
    preferences[booleanPreferencesKey("isFirstLaunch")] ?: false
}

val userScoreFlow: Flow<Int> = dataStore.data.map { preferences ->
    preferences[intPreferencesKey("userScore")] ?: 0
}
```
[Data Storage in Android: SharedPreferences and Preferences DataStore](https://medium.com/@humzakhalid94/simplifying-data-storage-in-android-sharedpreferences-and-preferences-datastore-e775825d8d0c)

(ii)Proto datastore

ProtoDataStore is designed to store more complex.It's a good choice when you need to store custom objects or structured data that requires efficient serialization and deserialization.

```kotlin
val dataStore = context.createDataStore(name = "my_proto_preferences")

// Define a protobuf data class
@Serializable
data class UserData(val id: Int, val name: String)

// Reading data
val userData: Flow<UserData?> = dataStore.data
    .map { preferences ->
        preferences[USER_DATA_KEY]
    }

// Writing data
suspend fun setUserData(newUser: UserData) {
    dataStore.edit { preferences ->
        preferences[USER_DATA_KEY] = newUser
    }
}
```