Preferencje DataStore
Zastąp SharedPreferences nowoczesną biblioteką DataStore. Odczytuj dane jako Kotlin Flow, zapisuj je za pomocą edit{} i bezpiecznie obsługuj błędy.
Preferencje DataStore to bezpłatna lekcja Android Academy na CoddyKit. To lekcja 5 z 6. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Android Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Android Academy zawiera 6 lekcji w sumie.
Dlaczego DataStore?
DataStore to nowoczesny zamiennik SharedPreferences. Rozwiązuje rzeczywiste problemy:
- SharedPreferences blokuje wątek interfejsu użytkownika — DataStore jest w pełni asynchroniczny
- SharedPreferences może zgłaszać nieobsłużone wyjątki — DataStore obsługuje błędy za pośrednictwem Flow
- DataStore zapewnia bezpieczeństwo typów (Preferences) lub bezpieczeństwo schematu (Proto)
- Działa natywnie z Kotlin Coroutines i Flow
Dwa typy DataStore
Proszę wybrać właściwy typ do danego zastosowania:
- Preferences DataStore — pary klucz–wartość, bez potrzeby definiowania schematu. Najprostszy w konfiguracji. Najlepszy do ustawień aplikacji i preferencji użytkownika.
- Proto DataStore — obiekty typowane za pomocą Protocol Buffers. Wymaga pliku schematu .proto. Najlepszy w przypadku danych o ustrukturyzowanej strukturze.
Ta lekcja dotyczy Preferences DataStore.
Dodawanie zależności
Proszę dodać DataStore do pliku app/build.gradle:
// app/build.gradle
dependencies {
implementation 'androidx.datastore:datastore-preferences:1.1.1'
// Coroutines (likely already in your project)
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3'
}Tworzenie instancji DataStore
Proszę utworzyć DataStore jednokrotnie za pomocą delegata najwyższego poziomu. Zwykle robi się to w osobnym pliku:
import android.content.Context
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.preferencesDataStore
// Top-level property — creates a single DataStore instance per Context
val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "user_prefs")Definiowanie kluczy
Klucze są obiektami zapewniającymi bezpieczeństwo typów, a nie zwykłymi ciągami znaków. Proszę utworzyć je za pomocą odpowiedniej funkcji fabrykującej:
import androidx.datastore.preferences.core.booleanPreferencesKey
import androidx.datastore.preferences.core.intPreferencesKey
import androidx.datastore.preferences.core.stringPreferencesKey
object PreferencesKeys {
val DARK_MODE = booleanPreferencesKey("dark_mode")
val USER_NAME = stringPreferencesKey("user_name")
val LAUNCH_COUNT = intPreferencesKey("launch_count")
}Zapisywanie danych
Dane należy zapisywać wewnątrz korutyny za pomocą edit { }:
import androidx.datastore.preferences.core.edit
// In a ViewModel or Repository:
suspend fun saveDarkMode(enabled: Boolean) {
context.dataStore.edit { prefs ->
prefs[PreferencesKeys.DARK_MODE] = enabled
}
}
suspend fun incrementLaunchCount() {
context.dataStore.edit { prefs ->
val current = prefs[PreferencesKeys.LAUNCH_COUNT] ?: 0
prefs[PreferencesKeys.LAUNCH_COUNT] = current + 1
}
}Odczytywanie danych za pomocą Flow
DataStore udostępnia dane jako Flow. Proszę użyć map, aby wyodrębnić potrzebną wartość:
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
val darkModeFlow: Flow<Boolean> = context.dataStore.data
.map { prefs ->
prefs[PreferencesKeys.DARK_MODE] ?: false // default = false
}
val userNameFlow: Flow<String> = context.dataStore.data
.map { prefs ->
prefs[PreferencesKeys.USER_NAME] ?: "Guest"
}Zbieranie danych w ViewModel
Proszę udostępniać Flow z DataStore z poziomu ViewModel, używając stateIn w celu wydajnego zbierania danych:
class SettingsViewModel(private val repo: SettingsRepository) : ViewModel() {
val isDarkMode: StateFlow<Boolean> = repo.darkModeFlow
.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5000),
initialValue = false
)
fun toggleDarkMode(enabled: Boolean) {
viewModelScope.launch {
repo.saveDarkMode(enabled)
}
}
}Obserwowanie w Activity/Fragment
Proszę zbierać StateFlow w interfejsie użytkownika za pomocą lifecycleScope.launch:
// In Fragment:
lifecycleScope.launch {
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.isDarkMode.collect { darkMode ->
binding.switchDarkMode.isChecked = darkMode
AppCompatDelegate.setDefaultNightMode(
if (darkMode) AppCompatDelegate.MODE_NIGHT_YES
else AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
)
}
}
}Obsługa błędów
DataStore emituje IOException, jeśli plik jest uszkodzony. Proszę przechwycić ten wyjątek w potoku Flow:
import kotlinx.coroutines.flow.catch
import java.io.IOException
val safeFlow: Flow<Boolean> = context.dataStore.data
.catch { exception ->
if (exception is IOException) {
emit(emptyPreferences()) // return defaults
} else {
throw exception
}
}
.map { prefs ->
prefs[PreferencesKeys.DARK_MODE] ?: false
}DataStore a SharedPreferences
Podsumowanie powodów, dla których DataStore jest lepszym rozwiązaniem:
- DataStore automatycznie odczytuje i zapisuje dane w tle — nie ma ryzyka ANR
- Wywołanie
apply()w SharedPreferences może zakończyć się niepowodzeniem bez informacji; DataStore przekazuje błędy za pośrednictwem Flow - DataStore jest reaktywny — interfejs użytkownika automatycznie aktualizuje się po zmianie danych
- SharedPreferences nie oferuje ścieżki migracji; DataStore ma wbudowany mechanizm
SharedPreferencesMigration
Szybkie sprawdzenie
Jaki jest główny mechanizm używany przez DataStore do udostępniania danych pozostałej części aplikacji?
Podsumowanie: DataStore Preferences
DataStore to nowoczesny sposób przechowywania prostych danych:
- Dodanie zależności
datastore-preferences - Utworzenie jednej instancji za pomocą delegata
preferencesDataStore - Definiowanie kluczy zapewniających bezpieczeństwo typów za pomocą funkcji
stringPreferencesKey,booleanPreferencesKeyitd. - Zapisywanie danych za pomocą
dataStore.edit { }wewnątrz korutyny - Odczytywanie danych jako
Flowza pomocądataStore.data.map { } - Obsługa
IOExceptionza pomocą.catch { emit(emptyPreferences()) }
Następnie: tworzenie wydajnych adapterów list za pomocą DiffUtil.
Często zadawane pytania
Czy lekcja „Preferencje DataStore” jest bezpłatna?
Tak — pełny tekst „Preferencje DataStore” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Android Academy, przejdź na CoddyKit PRO. Kurs Android Academy zawiera 6 lekcji w sumie.
Co nauczysz się w „Preferencje DataStore”?
Zastąp SharedPreferences nowoczesną biblioteką DataStore. Odczytuj dane jako Kotlin Flow, zapisuj je za pomocą edit{} i bezpiecznie obsługuj błędy. Ćwiczysz Android Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć Android Academy?
Nie wymagamy żadnego doświadczenia. Android Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 5 z 6.
Ile czasu zajmuje lekcja „Preferencje DataStore”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji Android Academy?
Tak. Każda lekcja Android Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Kolekcje w Kotlinie
- Podstawy RecyclerView
- Obsługa kliknięć w RecyclerView
- SharedPreferences
- Preferencje DataStore
- Adaptery i DiffUtil