用戶登錄後,用戶名、頭像、Token 等信息需在多 Activity/Fragment/Service 中頻繁讀寫。
| 方案 | 優勢 | 劣勢 | 適用場景 |
|---|---|---|---|
| 自定義 Application 類持有靜態/實例字段 | 極快、無序列化開銷、支持任意對象 | 進程被殺後數據丟失、內存洩漏風險、不支持跨進程 | 臨時緩存、非持久化需求 |
| SharedPreferences (XML) | 輕量、進程安全、自動持久化 | 同步寫入阻塞主線程、不支持複雜對象、apply() 異步無回調 | 少量鍵值對、用戶偏好設定 |
| Jetpack DataStore (Preferences/Proto) | 基於協程/Flow、主線程安全、支持遷移、類型安全 | 需學習 Flow、Proto 需定義 schema | 現代應用首選、替代 SP |
| Room Database | SQL 能力、觀察者模式 (LiveData/Flow)、編譯期驗證、支持複雜查詢 | 樣板代碼多、遷移麻煩、體積較大 | 結構化數據、列表、關聯查詢 |
| MMKV (騰訊開源) | 極高性能 (mmap)、支持多進程、加密、自動異步刷盤 | 第三方依賴、非 Google 官方 | 高頻讀寫、大對象、替代 SP/DataStore |
// UserRepository.kt
class UserRepository @Inject constructor(
private val dataStore: DataStore,
private val api: UserApi
) {
private val _user = MutableStateFlow(null)
val user: StateFlow = _user
suspend fun load() {
val prefs = dataStore.data.first() // 或 collectAsStateFlow()
val token = prefs[TOKEN_KEY] ?: ""
if (token.isNotBlank()) {
_user.value = User(token, prefs[NAME_KEY]!!, prefs[AVATAR_KEY]!!)
}
}
suspend fun login(account: String, pwd: String) {
val resp = api.login(account, pwd)
dataStore.edit { it[TOKEN_KEY] = resp.token; it[NAME_KEY] = resp.name; it[AVATAR_KEY] = resp.avatar }
_user.value = User(resp.token, resp.name, resp.avatar)
}
fun getUserSync() = _user.value // 同步快速讀取
}
viewModel.user.observe(this) { updateUI(it) };repository.getUserSync() 或 withContext(Dispatchers.IO) { dataStore.data.first() };edit().commit() 嚴禁主線程調用,務必用 apply() 或遷移 DataStore;現代 Android 開發首選 DataStore + Repository 模式,兼顧性能、類型安全、主線程友好與生命周期感知。舊項目可漸進式遷移,新項目直接上 DataStore/Room/MMKV。