Trwałe przechowywanie danych zapewnia zachowanie informacji użytkownika między sesjami aplikacji mobilnej. Bez tej technologii każde uruchomienie programu zaczynałoby się od zera — ustawienia, historia i pobrane pliki byłyby tracone przy zamknięciu. Według danych Google Developers, 2024, ponad 90% aplikacji mobilnych używa co najmniej jednego mechanizmu trwałego przechowywania do zapisywania danych użytkownika i stanu interfejsu.
Najważniejsze
Data Persistence — to zdolność aplikacji do zapisywania danych w nieulotnej pamięci urządzenia. W programowaniu mobilnym trwałe przechowywanie obejmuje bazy danych, system plików, ustawienia i pamięć podręczną. Każdy mechanizm ma swoje cechy dotyczące wydajności, bezpieczeństwa i pojemności przechowywanych informacji.
Dane tymczasowe istnieją tylko w pamięci RAM i są tracone po zakończeniu procesu. Należą do nich stan ekranu, obliczenia tymczasowe i pamięć podręczna obrazów. Dane trwałe są zapisywane w systemie plików lub bazie danych i pozostają dostępne po ponownym uruchomieniu aplikacji. Należą do nich ustawienia użytkownika, tokeny autoryzacji, historia operacji i pobrane treści.
Przy wyborze sposobu przechowywania danych programista ocenia kilka czynników. Typ danych określa strukturę przechowywania: proste ustawienia — SharedPreferences lub DataStore, ustrukturyzowane rekordy — SQLite lub Room, pliki — File Storage. Ilość danych wpływa na wydajność: bazy danych są zoptymalizowane dla tysięcy rekordów, a pliki dla dużych obiektów binarnych. Bezpieczeństwo wymaga szyfrowania poufnych informacji za pomocą EncryptedSharedPreferences lub SQLCipher.
data class StorageOption(
name: String,
dataType: StorageType,
capacity: Long,
secure: Boolean
)
enum class StorageType {
KEY_VALUE,
RELATIONAL,
FILE
}
SharedPreferences — klasyczny sposób przechowywania par klucz-wartość na Android. To API istnieje od pierwszych wersji platformy i obsługuje typy pierwotne: ciągi znaków, liczby, wartości logiczne. Dane są przechowywane w pliku XML w prywatnym katalogu aplikacji i są dostępne tylko dla jej procesu.
Jetpack DataStore — nowoczesny zamiennik SharedPreferences, zbudowany na Kotlin Coroutines i Flow. DataStore oferuje dwa warianty: Preferences DataStore dla prostych wartości i Proto DataStore dla typizowanych obiektów. W przeciwieństwie do SharedPreferences, DataStore gwarantuje spójność danych przy współbieżnym dostępie i obsługuje operacje asynchroniczne bez blokowania głównego wątku.
// SharedPreferences — tradycyjny sposób
val prefs = context
.getSharedPreferences("settings", Context.MODE_PRIVATE)
with (prefs.edit()) {
putString("username", "john_doe")
putInt("score", 1500)
apply()
}
// DataStore — podejście asynchroniczne
val settingsDataStore = context
.createDataStore("settings.pb")
val usernameFlow: Flow<String> = settingsDataStore
.data
.map { it[USERNAME_KEY] ?: "" }
Na iOS odpowiednikiem SharedPreferences jest UserDefaults — system przechowywania prostych wartości w formacie Property List. UserDefaults używa synchronicznego dostępu i nadaje się do małych ilości danych konfiguracyjnych, ale nie jest zalecany do przechowywania poufnych informacji.
SQLite — wbudowana relacyjna baza danych, która działa wewnątrz procesu aplikacji bez osobnego serwera. To najpopularniejszy system DBMS w programowaniu mobilnym: jest domyślnie używany na obu platformach. Android zawiera SQLite w SDK, a iOS w bibliotece libsqlite3. SQLite obsługuje standardowy SQL, transakcje, indeksy i wyzwalacze.
Praca z SQLite zaczyna się od utworzenia schematu bazy danych. Programista definiuje tabele, ich pola i typy, a następnie wykonuje operacje wstawiania, odczytu, aktualizacji i usuwania. SQLiteOpenHelper na Android zarządza tworzeniem i migracjami bazy, a na iOS używany jest interfejs C lub nakładka FMDB.
// SQLiteOpenHelper na Android
class DBHelper(context: Context) :
SQLiteOpenHelper(context, "app.db", null, 1) {
override fun onCreate(db: SQLiteDatabase) {
db.execSQL("""
CREATE TABLE users (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
email TEXT UNIQUE
)
""")
}
fun insertUser(name: String, email: String) {
val db = writableDatabase
val values = ContentValues().apply {
put("name", name)
put("email", email)
}
db.insert("users", null, values)
}
}
| Typ danych | SharedPreferences | SQLite | System plików |
|---|---|---|---|
| Typ | klucz-wartość | relacyjna baza danych | pliki binarne |
| Pojemność | setki rekordów | tysiące rekordów | dostępne miejsce |
| Wydajność | wysoka | średnia | zależy od rozmiaru |
| Typowe zastosowanie | ustawienia | ustrukturyzowane dane | obrazy, wideo |
Room — biblioteka z pakietu Jetpack, zapewniająca warstwę ORM na SQLite. Room eliminuje rutynową pracę związaną z pisaniem zapytań SQL i ContentValues, zastępując je adnotacjami i funkcjami Kotlin. Kompilator Room generuje implementację DAO (Data Access Object) na etapie budowania, co eliminuje błędy w składni SQL.
Aby podłączyć Room, należy dodać zależność kapt i adnotować klasę encji, interfejs DAO oraz klasę bazy danych. RoomDatabase służy jako punkt wejścia: przez niego uzyskuje się DAO i wykonuje operacje na bazie. Room obsługuje Flow dla zapytań reaktywnych, migracje schematu i sprawdzanie zapytań na etapie kompilacji.
@Entity(tableName = "users")
data class User(
@PrimaryKey val id: Int,
@ColumnInfo(name = "full_name") val name: String,
@ColumnInfo val email: String
)
@Dao
interface UserDao {
@Query("SELECT * FROM users")
fun getAll(): Flow<List<User>>
@Insert
suspend fun insert(user: User)
@Delete
suspend fun delete(user: User)
}
@Database(
entities = [User::class],
version = 1
)
abstract class AppDatabase : RoomDatabase() {
abstract fun userDao(): UserDao
}
Core Data — framework Apple do zarządzania grafem obiektów i ich zapisywania na dysk. W przeciwieństwie do Room, Core Data nie działa na tabelach, lecz na zarządzanych obiektach (NSManagedObject), które tworzą hierarchię powiązań. Core Data obsługuje leniwe ładowanie, cofanie zmian i złożone zapytania przez NSFetchRequest.
Podstawę Core Data stanowi stos trzech komponentów: zarządzany kontekst (NSManagedObjectContext), trwałe przechowywanie (NSPersistentStoreCoordinator) i model danych (NSManagedObjectModel). NSPersistentContainer łączy wszystkie komponenty w jeden punkt wejścia, upraszczając konfigurację dla nowoczesnych aplikacji w Swift.
import CoreData
class PersistenceController {
static let shared = PersistenceController()
let container: NSPersistentContainer
init() {
container = NSPersistentContainer(name: "AppModel")
container.loadPersistentStores { _, error in
if let error = error {
fatalError("Failed: \(error)")
}
}
}
func saveUser(name: String, email: String) {
let context = container.viewContext
let user = User(context: context)
user.name = name
user.email = email
do {
try context.save()
} catch let error {
print("Błąd zapisu: \(error)")
}
}
}
Przechowywanie plików (File Storage) jest używane do zapisywania obrazów, wideo i dokumentów. Android zapewnia pamięć wewnętrzną (context.filesDir) — prywatną dla aplikacji, i zewnętrzną (Environment.getExternalStorageDirectory) — dostępną dla innych aplikacji. Na iOS pliki są zapisywane w katalogach Documents i Library, przy czym Library/Caches jest przeznaczona dla pamięci podręcznej, która nie podlega kopii zapasowej w iCloud. Do pracy z plikami obie platformy udostępniają File API oraz operacje strumieniowego odczytu i zapisu. Nowoczesne biblioteki takie jak Coil i SDWebImage dodają warstwę buforowania, łącząc przechowywanie plików z pamięcią RAM dla optymalnej wydajności.
Na Android alternatywą dla Core Data pod względem złożoności i funkcjonalności jest Realm — obiektowa baza danych, która działa bezpośrednio na modelach bez warstwy SQL. Realm jest szybszy od SQLite w operacjach odczytu i obsługuje live-obiekty, które automatycznie aktualizują UI przy zmianie danych.
Często zadawane pytania
Data Persistence — to mechanizmy zapisywania danych w nieulotnej pamięci urządzenia, zapewniające ich dostępność po ponownym uruchomieniu aplikacji. Należą do nich bazy danych, przechowywanie plików i systemy ustawień.
Room to nakładka ORM na SQLite, która eliminuje ręczne pisanie zapytań SQL i ContentValues. Room sprawdza zapytania SQL na etapie kompilacji, obsługuje Kotlin Coroutines i Flow, a także automatycznie generuje kod dostępu do danych.
SharedPreferences nadaje się do przechowywania niewielkiej ilości prostych danych: ustawień aplikacji, flag, identyfikatorów i preferencji użytkownika. Do złożonych lub ustrukturyzowanych danych lepiej użyć Room lub DataStore.
Core Data — framework Apple do zarządzania grafem obiektów. Zapewnia pracę z zarządzanymi obiektami, śledzenie zmian, leniwe ładowanie i automatyczne zapisywanie do trwałego przechowywania (SQLite, XML lub format binarny).
Wybór zależy od złożoności danych: dla ustawień — DataStore lub UserDefaults, dla ustrukturyzowanych rekordów — Room (Android) lub Core Data (iOS), dla plików — File Storage. Kryteria obejmują ilość danych, wymagania dotyczące wydajności i potrzebę szyfrowania. Łączenie kilku mechanizmów w jednej aplikacji to standardowa praktyka, pozwalająca optymalnie wykorzystać mocne strony każdego podejścia.
Podsumowanie
Opracujemy aplikację mobilną pod klucz
IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.
Przeczytaj również