Skip to Content

DataStore trong Android

1. Giới thiệu

DataStore là giải pháp lưu trữ data thay thế SharedPreferences, an toàn với coroutines và Flow.

So sánh với SharedPreferences

FeatureSharedPreferencesDataStore
Async API
Main thread safe
Error handling
Type safety✅ (Proto)
Migration

2. Setup

// build.gradle.kts dependencies { implementation("androidx.datastore:datastore-preferences:1.1.1") }

3. Preferences DataStore

Tạo DataStore

val Context.dataStore: DataStore<Preferences> by preferencesDataStore( name = "settings" )

Định nghĩa Keys

object PreferencesKeys { val USERNAME = stringPreferencesKey("username") val AGE = intPreferencesKey("age") val IS_LOGGED_IN = booleanPreferencesKey("is_logged_in") val SCORE = floatPreferencesKey("score") }

Đọc dữ liệu

class SettingsRepository(private val context: Context) { val usernameFlow: Flow<String> = context.dataStore.data .map { preferences -> preferences[PreferencesKeys.USERNAME] ?: "" } val settingsFlow: Flow<UserSettings> = context.dataStore.data .map { preferences -> UserSettings( username = preferences[PreferencesKeys.USERNAME] ?: "", age = preferences[PreferencesKeys.AGE] ?: 0, isLoggedIn = preferences[PreferencesKeys.IS_LOGGED_IN] ?: false ) } }

Ghi dữ liệu

suspend fun saveUsername(username: String) { context.dataStore.edit { preferences -> preferences[PreferencesKeys.USERNAME] = username } } suspend fun saveSettings(settings: UserSettings) { context.dataStore.edit { preferences -> preferences[PreferencesKeys.USERNAME] = settings.username preferences[PreferencesKeys.AGE] = settings.age preferences[PreferencesKeys.IS_LOGGED_IN] = settings.isLoggedIn } }

4. Sử dụng với ViewModel

class SettingsViewModel( private val repository: SettingsRepository ) : ViewModel() { val settings: StateFlow<UserSettings> = repository.settingsFlow .stateIn( scope = viewModelScope, started = SharingStarted.WhileSubscribed(5000), initialValue = UserSettings() ) fun updateUsername(username: String) { viewModelScope.launch { repository.saveUsername(username) } } }

5. Sử dụng với Compose

@Composable fun SettingsScreen(viewModel: SettingsViewModel = viewModel()) { val settings by viewModel.settings.collectAsState() Column { Text("Username: ${settings.username}") var newUsername by remember { mutableStateOf("") } OutlinedTextField( value = newUsername, onValueChange = { newUsername = it }, label = { Text("New Username") } ) Button(onClick = { viewModel.updateUsername(newUsername) }) { Text("Save") } } }

6. Error Handling

val settingsFlow: Flow<UserSettings> = context.dataStore.data .catch { exception -> if (exception is IOException) { emit(emptyPreferences()) } else { throw exception } } .map { preferences -> UserSettings(...) }

7. Migration từ SharedPreferences

val Context.dataStore by preferencesDataStore( name = "settings", produceMigrations = { context -> listOf(SharedPreferencesMigration(context, "old_prefs_name")) } )

8. Proto DataStore (Type-safe)

Setup

// build.gradle.kts plugins { id("com.google.protobuf") version "0.9.4" } dependencies { implementation("androidx.datastore:datastore:1.1.1") implementation("com.google.protobuf:protobuf-javalite:3.25.1") }

Định nghĩa Proto

// src/main/proto/settings.proto syntax = "proto3"; message Settings { string username = 1; int32 age = 2; bool is_logged_in = 3; }

Serializer

object SettingsSerializer : Serializer<Settings> { override val defaultValue: Settings = Settings.getDefaultInstance() override suspend fun readFrom(input: InputStream): Settings { return Settings.parseFrom(input) } override suspend fun writeTo(t: Settings, output: OutputStream) { t.writeTo(output) } }

Sử dụng Proto DataStore

val Context.settingsDataStore: DataStore<Settings> by dataStore( fileName = "settings.pb", serializer = SettingsSerializer ) // Read val settingsFlow: Flow<Settings> = context.settingsDataStore.data // Write suspend fun updateUsername(username: String) { context.settingsDataStore.updateData { current -> current.toBuilder() .setUsername(username) .build() } }

📝 Tóm tắt

TypeUse Case
Preferences DataStoreKey-value đơn giản
Proto DataStoreType-safe, complex objects
APIMô tả
dataStore.dataFlow of preferences
dataStore.edit {}Modify data
map {}Transform data
catch {}Handle errors
Last updated on