Chapters

Hide chapters

Kotlin Multiplatform by Tutorials

Third Edition · Android 15, iOS 18, Desktop · Kotlin 2.1.20 · Android Studio Meerkat

10. Data Persistence
Written by Saeed Taheri

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now

The big elephant in the room of the Organize app is that it doesn’t remember anything you add into it. As soon as you close the app or stop the debugger, every TODO item disappears for good.

The reason for this issue is that it’s storing everything in memory and — surprisingly enough — computer memory, or to be more exact the RAM, may remind people of Dory the fish!

Apps can persist their data if they store them on non-volatile storage. Examples of this type of storage are HDD, or Hard Disk Drive, SSD, or Solid-State Storage, and Flash Storage.

Putting aside the details of how computers work and going more high level, you can mostly persist data using three different mechanisms:

  1. Key-Value Storage
  2. Database
  3. File system

In this chapter, you’ll learn about the first two options, which are more structured and more straightforward than working with file systems directly.

Key-Value Storage

One of the most common use cases when persisting data is to store bits of information in a dictionary or map style.

You may have heard of SharedPreferences on Android or UserDefaults on iOS. As both the names imply, people use these mostly to store user preferences and settings.

Since the setup process for using each of these classes is platform-specific, you could use the old and sweet expect/actual mechanism to create a single interface for accessing key-value storage on each platform. Although you completely know how to do this manually, it’s a lot of boilerplate code to write.

Fortunately, there’s a library named Multiplatform Settings that does most of the heavy lifting for you.

In this part of the chapter, you’ll take advantage of the Multiplatform Settings library to store the first time you opened a specific page in the Organize app.

Setting Up Multiplatform Settings

There are two ways of setting up the library.

Android

Still in the shared module, create KoinAndroid.kt inside androidMain as a sibling to Platform.kt and add this block of code:

iOS

Open KoinIOS.kt from iosMain inside the shared module and add the actual implementation of platformModule constant:

Desktop

Create KoinDesktop.kt inside the desktopMain directory as a sibling to Platform.kt and add the actual implementation for platformModule.

Storing Values Using Multiplatform Settings

In this part, you’ll store the first time you open the About Device page.

Android

First, open OrganizeApp.kt in androidApp and update the creation of AboutViewModel in the viewModel block to account for the added parameter in its constructor.

Wad. 38.1 — Jqe Aqaec qoxu ef Ajrwiev
Piv. 48.8 — Wve Uluaq boyu eh Ahdxeir

iOS

Open iosApp.xcodeproj and go to AboutListView.swift. First, add a property for the footer as you did for the Android counterpart:

Goy. 69.8 — Sgi Upuuy vuku ej iUZ
Wid. 54.5 — Whu Ifaim zabu ar aUL

Desktop

Open AboutView.kt in the desktopApp module. Change the ContentView composable function to accept a footer, and then show it at the bottom of row items. It’s the same definition of the ContentView in the androidApp module. You can look back at the implementation above.

Daf. 20.7 — Mlo Uzoad hunu ok Lowbluv
Yah. 44.3 — Xse Ijoin pezi ap Tavstat

Database

A database is an organized collection of data. Whenever you’re dealing with a structured set of data that you need to access in a certain way, it’s a good choice to use a database over directly messing with the file system.

SQL

SQL is a database querying language, and you shouldn’t mistake it for the database itself. There are many databases that use SQL specifications — SQLDelight is only one of them.

Setting Up SQLDelight

You need to apply the SQLDelight Gradle plugin in your project.

Database Helper

To make executing database actions easier, it’s a good practice to create a common interface that abstracts the database you’re using. During the lifetime of your app, you might need to switch the underlying database for some reason.

Using the Database in the App

You should inject an instance of the DatabaseHelper class you created to wherever you want to use the database. From an architectural standpoint, repositories are a great place to do so.

Android

Open KoinAndroid.kt in androidMain and add a singleton definition underneath the Settings declaration as follows:

iOS

Open KoinIOS.kt and set this as the platformModule actual property:

Desktop

Open KoinDesktop.kt, and add the SqlDriver module definition as follows:

Migration

Imagine one day you decide to add a new feature to the app: setting due dates on each reminder. This means you need to update many things throughout your code. One of the most important parts is the database schema. Although delicate, it’s pretty straightforward to do.

Dap. 88.6 — Pijidole Walirizi Hgnopa Ckusva Mayz
Yut. 22.9 — Vupejili Pojotopa Tksuxi Stoqyu Jurj

Zuv. 70.8 — Revatg VhvMuxugxb Walbavuiw Wlirhi Nirn
Neb. 39.5 — Lifefw BvbFesaxqs Jihlecaod Ntexdi Fasr

Adding Coroutines

Take a look at how you set up RemindersViewModel, and you’ll remember that you needed to invoke the onRemindersUpdated lambda to notify users of the ViewModel of potential changes.

Challenge

Databases have four basic operations: Create, Read, Update and Delete, a.k.a. CRUD. In Organize, you used three of those operations. Implementing the only remaining one — Delete — is a suitable candidate for a challenge.

Challenge: Adding Support for Deleting Reminders

Add a feature to Organize that lets the user delete reminders individually. For the UI part, you may take advantage of swipe gestures on Android and iOS. On desktop, you can use a context menu that’s displayed when the user right-clicks on any reminder.

Key Points

  • There are three major ways of persisting data on a device: Key-Value storage, database and working directly with the file system.
  • Multiplatform Settings is a library that simplifies the process of storing small bits of data in a dictionary-style.
  • You can use databases to store structured data and access them in a certain way.
  • SQLDelight is a relationally based database that generates typesafe Kotlin API based on the SQL statements you write. When used in KMP, it uses SQLite under the hood.
  • Migrating databases is a delicate and important step when you want to change your database schema.
  • SQLDelight has an extension library that lets you observe database changes using Kotlin Flows.

Where to Go From Here?

This has been a long chapter. However, there remains lots of ground to cover.

Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum here.
© 2026 Kodeco Inc.

You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now