告別SharedPreferences!用DataStore打造更靠譜的本地存儲
DataStore
作為Android官方推薦的新一代數據存儲方案,完美解決了SharedPreferences
的三大痛點:
1. 主線程卡頓終結者
所有讀寫操作自動切到子線程,再也不用擔心用戶點按鈕時卡住界面。對比之下SharedPreferences
的commit()
方法就像在早高峰的主干道上調頭。
2. 類型安全不翻車
用ProtoDataStore
可以像寫類一樣定義數據結構,徹底告別SharedPreferences
里把字符串當數字用的尷尬場景。
3. 數據保險箱機制
自帶"原子操作"屬性,就算突然斷電也不會出現存了一半的殘缺數據。這就像銀行轉賬,要么成功要么失敗,絕不會有中間狀態。
手把手教你兩種用法
簡單配置存儲(Preferences版)
適用場景:比如記住用戶設置的夜間模式、字體大小等簡單配置
// 第一步:在build.gradle添加
dependencies {
implementation 'androidx.datastore:datastore-preferences:1.1.1'
}
// 第二步:創建存儲文件(放在Application類里)
val Context.appSettings by preferencesDataStore(name = "user_prefs")
// 第三步:定義要存的字段
object PrefsKeys {
val DARK_MODE = booleanPreferencesKey("dark_mode")
val FONT_SIZE = intPreferencesKey("font_size")
}
// 第四步:讀寫操作
classSettingsRepository(privateval context: Context) {
// 讀取設置
val darkModeFlow: Flow<Boolean> = context.appSettings.data
.map { prefs -> prefs[PrefsKeys.DARK_MODE] ?: false }
// 修改設置
suspendfun toggleDarkMode(enable: Boolean) {
context.appSettings.edit { settings ->
settings[PrefsKeys.DARK_MODE] = enable
}
}
}
復雜數據存儲(Proto版)
適用場景:存儲用戶游戲存檔、購物車信息等結構化數據
// 第一步:定義proto結構(新建settings.proto文件)
syntax = "proto3";
message GameSave {
int32 current_level = 1;
repeated string unlocked_items = 2;
map<string, int32> equipment_stats = 3;
}
// 第二步:生成Java類(Build -> Rebuild Project)
// 第三步:實現序列化器
object GameSaveSerializer : Serializer<GameSave> {
overrideval defaultValue = GameSave.getDefaultInstance()
overridesuspendfun readFrom(input: InputStream) =
try { GameSave.parseFrom(input) }
catch (e: Exception) { throw CorruptionException("存檔損壞", e) }
overridesuspendfun writeTo(data: GameSave, output: OutputStream) =
data.writeTo(output)
}
// 第四步:創建DataStore實例
val Context.gameData by dataStore("game_saves.pb", GameSaveSerializer)
// 第五步:操作游戲存檔
classGameSaveManager(privateval context: Context) {
// 讀取關卡進度
val currentLevelFlow: Flow<Int> =
context.gameData.data.map { it.currentLevel }
// 解鎖新道具
suspendfun unlockItem(itemName: String) {
context.gameData.updateData { current ->
current.toBuilder()
.addUnlockedItems(itemName)
.build()
}
}
}
開發避坑指南
1.單例原則
每個存儲文件只能創建一個DataStore
實例,建議在Application
類初始化
2.遷移老數據dataStore.migrateFrom(sharedPrefs)
一鍵遷移,記得先停用舊的SharedPreferences
3.多進程場景
用這個特殊創建方式保證數據安全:
val multiProcessStore = MultiProcessDataStoreFactory.create(
serializer = GameSaveSerializer(),
produceFile = { File(context.filesDir, "multi_process_data.pb") }
)
4.異常處理
在Flow
收集時加上catch
處理:
context.gameData.data
.catch { ex ->
if (ex is CorruptionException) recoverFromCorruption()
}
.collect { gameSave -> updateUI(gameSave) }
什么時候該用DataStore?
- 需要存用戶個性化設置
- 需要緩存接口返回的簡單數據
- 需要保存應用狀態(比如表單草稿)
- 需要跨進程共享數據
?? 需要存大量結構化數據 → 考慮Room數據庫
?? 需要存圖片/視頻 → 直接用文件存儲
升級到DataStore后,你會發現代碼里少了無數個getSharedPreferences(),再也不用寫commit()和apply()的糾結選擇,數據操作就像用LiveData一樣流暢自然。