Article image Data Persistence in Android

26. Data Persistence in Android

Page 26 | Listen in audio

Data persistence is a crucial aspect of mobile app development, particularly for Android applications. It involves saving data in a way that it remains available even after the app is closed or the device is restarted. This ensures that users have a seamless experience with their data intact across sessions. In this section, we will delve into the various methods of data persistence available in Android, focusing on how they can be utilized in Kotlin for Android app development.

Android provides several options for data persistence, each with its own use cases and advantages. These include SharedPreferences, SQLite databases, Room Persistence Library, and file storage. Understanding when and how to use each of these options is key to building robust and efficient Android applications.

SharedPreferences

SharedPreferences is one of the simplest ways to store small amounts of primitive data in key-value pairs. This is particularly useful for saving user preferences, settings, or any other data that doesn't require complex querying or structuring.

To use SharedPreferences in Kotlin, you can access it via the getSharedPreferences() method. Here's a basic example:


val sharedPreferences = context.getSharedPreferences("MyPrefs", Context.MODE_PRIVATE)
val editor = sharedPreferences.edit()
editor.putString("username", "JohnDoe")
editor.putInt("userId", 123)
editor.apply()

Reading data from SharedPreferences is straightforward:


val username = sharedPreferences.getString("username", null)
val userId = sharedPreferences.getInt("userId", -1)

While SharedPreferences is easy to use, it's not suitable for complex data structures or large datasets. For more complex data, you should consider using SQLite or Room.

SQLite Databases

SQLite is a lightweight, relational database management system embedded in Android. It allows you to perform complex queries and transactions, making it suitable for apps that require structured data storage.

To use SQLite in Kotlin, you typically extend the SQLiteOpenHelper class. Here's a basic example:


class MyDatabaseHelper(context: Context) : SQLiteOpenHelper(context, DATABASE_NAME, null, DATABASE_VERSION) {
    override fun onCreate(db: SQLiteDatabase) {
        val createTable = "CREATE TABLE Users (id INTEGER PRIMARY KEY, username TEXT, email TEXT)"
        db.execSQL(createTable)
    }

    override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
        db.execSQL("DROP TABLE IF EXISTS Users")
        onCreate(db)
    }
}

Once you have your database helper, you can perform CRUD operations:


val dbHelper = MyDatabaseHelper(context)
val db = dbHelper.writableDatabase

// Insert
val values = ContentValues().apply {
    put("username", "JohnDoe")
    put("email", "[email protected]")
}
db.insert("Users", null, values)

// Query
val cursor = db.query("Users", arrayOf("id", "username", "email"), null, null, null, null, null)
while (cursor.moveToNext()) {
    val id = cursor.getInt(cursor.getColumnIndexOrThrow("id"))
    val username = cursor.getString(cursor.getColumnIndexOrThrow("username"))
    val email = cursor.getString(cursor.getColumnIndexOrThrow("email"))
}
cursor.close()

SQLite provides a powerful way to manage complex data, but working with raw SQL queries can be error-prone and cumbersome. This is where the Room Persistence Library comes into play.

Room Persistence Library

The Room Persistence Library is part of Android Jetpack and provides an abstraction layer over SQLite. It simplifies database operations and integrates seamlessly with Kotlin's coroutines and LiveData.

To use Room, you define your database schema using data classes and DAOs (Data Access Objects). Here's an example:


@Entity(tableName = "users")
data class User(
    @PrimaryKey(autoGenerate = true) val id: Int = 0,
    val username: String,
    val email: String
)

@Dao
interface UserDao {
    @Insert
    suspend fun insert(user: User)

    @Query("SELECT * FROM users")
    suspend fun getAllUsers(): List<User>
}

@Database(entities = [User::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
    abstract fun userDao(): UserDao
}

To access the database, you would typically create an instance of the Room database:


val db = Room.databaseBuilder(context, AppDatabase::class.java, "my-database").build()
val userDao = db.userDao()

// Using coroutines to perform database operations
GlobalScope.launch {
    userDao.insert(User(username = "JohnDoe", email = "[email protected]"))
    val users = userDao.getAllUsers()
}

Room not only reduces boilerplate code but also provides compile-time checks for SQL queries, making it a robust choice for database operations in Android.

File Storage

For data that doesn't fit well into a database or key-value store, file storage is a viable option. Android supports both internal and external file storage.

Internal storage is private to the app, and files stored here are removed when the app is uninstalled. You can write to internal storage using:


val fileOutputStream = context.openFileOutput("myfile.txt", Context.MODE_PRIVATE)
fileOutputStream.write("Hello, World!".toByteArray())
fileOutputStream.close()

Reading from internal storage is just as straightforward:


val fileInputStream = context.openFileInput("myfile.txt")
val inputStreamReader = InputStreamReader(fileInputStream)
val bufferedReader = BufferedReader(inputStreamReader)
val stringBuilder = StringBuilder()
var text: String? = null
while ({ text = bufferedReader.readLine(); text }() != null) {
    stringBuilder.append(text)
}
fileInputStream.close()

External storage is shared across apps and can be useful for files that the user might want to access outside of your app, such as photos or documents. However, it requires runtime permissions and careful handling due to its public nature.

Conclusion

Data persistence is a fundamental aspect of Android app development, and choosing the right method depends on the specific needs of your application. SharedPreferences is ideal for simple key-value data, SQLite and Room are suited for structured data with complex queries, and file storage is great for unstructured data or media files.

By leveraging Kotlin's features and Android's data persistence mechanisms, developers can create efficient, reliable, and user-friendly applications. Understanding these tools and knowing when to use them will greatly enhance your app development skills and lead to better user experiences.

Now answer the exercise about the content:

Which data persistence method in Android is particularly useful for saving small amounts of primitive data, such as user preferences or settings, in key-value pairs?

You are right! Congratulations, now go to the next page

You missed! Try again.

Article image Shared Preferences in Android

Next page of the Free Ebook:

27Shared Preferences in Android

8 minutes

Earn your Certificate for this Course for Free! by downloading the Cursa app and reading the ebook there. Available on Google Play or App Store!

Get it on Google Play Get it on App Store

+ 6.5 million
students

Free and Valid
Certificate with QR Code

48 thousand free
exercises

4.8/5 rating in
app stores

Free courses in
video, audio and text