DEV Community

Papon Ahasan
Papon Ahasan

Posted on • Edited on

App data and files

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.

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

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

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

  4. 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:

val filename = "myfile"
val fileContents = "Hello world!"
context.openFileOutput(filename, Context.MODE_PRIVATE).use {
        it.write(fileContents.toByteArray())
}
Enter fullscreen mode Exit fullscreen mode

Access a file:

context.openFileInput(filename).bufferedReader().useLines { lines ->
    lines.fold("") { some, text ->
        "$some\n$text"
    }
}
Enter fullscreen mode Exit fullscreen mode

Preferences

  1. 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:

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()
    }
}
Enter fullscreen mode Exit fullscreen mode

Access a data:

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

data a remove:

val sharedPref = this.getSharedPreferences("onBoarding", Context.MODE_PRIVATE)
sharedPref.edit().remove("splashFinished").apply()
Enter fullscreen mode Exit fullscreen mode
  1. 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"
Enter fullscreen mode Exit fullscreen mode

Creating a Preferences DataStore

val dataStore: DataStore<Preferences> = context.createDataStore(name = "my_preferences")
Enter fullscreen mode Exit fullscreen mode

Storing Data

// 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
    }
}
Enter fullscreen mode Exit fullscreen mode

Retrieving Data

val isFirstLaunchFlow: Flow<Boolean> = dataStore.data.map { preferences ->
    preferences[booleanPreferencesKey("isFirstLaunch")] ?: false
}

val userScoreFlow: Flow<Int> = dataStore.data.map { preferences ->
    preferences[intPreferencesKey("userScore")] ?: 0
}
Enter fullscreen mode Exit fullscreen mode

Data Storage in Android: SharedPreferences and Preferences DataStore

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

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
    }
}
Enter fullscreen mode Exit fullscreen mode

Top comments (0)