Android 可以使用 Java IO 流 (FileInputStream/OutputStream),但**強烈不建議**在註冊/登錄等業務場景直接手寫文件讀寫。Android 提供了更適合移動端的數據持久化機制。
| 方式 | 適用場景 | 優點 | 缺點 | 註冊/登錄推薦度 |
|---|---|---|---|---|
| SharedPreferences | 少量鍵值對 (用戶配置、Token、是否首次啟動、簡單用戶信息) | API 極簡、進程安全 (單進程)、支持數據類型自動轉換、適用于輕量級持久化 | 不支持複雜查詢、大量數據性能差、不支持對象直接存儲 (需序列化) | ⭐⭐⭐⭐⭐ 首選 (存 Token、UserId、自動登錄標識) |
| SQLite 數據庫 (Room) | 結構化數據、大量記錄、複雜查詢 (聊天記錄、商品列表、訂單) | 功能強大、支持事務/索引/外鍵、Room ORM 簡化開發、觀察者模式自動更新 UI | 樣板代碼多 (原生)、版本遷移麻煩、主線程操作會 ANR | ⭐⭐⭐ (存完整用戶表、多賬號切換) |
| 內部存儲 / 外部存儲 (文件) | 圖片、日誌、緩存、大文件下載、導出報表 | 空間大、可被用戶/其他應用訪問 (外部)、流式讀寫大文件高效 | 需手動管理路徑/編碼/異常、權限變動頻繁 (Android 10+ 分區存儲)、非結構化難查詢 | ⭐ (不推薦存用戶憑證) |
| DataStore (Jetpack) | 現代化鍵值/Protobuf 存儲,替代 SharedPreferences | 基於協程/Flow 異步、類型安全、事務性、無 ANR 風險 | 學習曲線稍陡、需遷移舊代碼 | ⭐⭐⭐⭐ (新項目首選) |
┌─────────────────────────────────────┐
│ 註冊/登錄 Activity │
└──────────────┬──────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ ViewModel / Repository │
│ (業務邏輯: 密碼加密、網絡請求、存儲) │
└──────────────┬──────────────────────┘
│
┌───────┴───────┐
▼ ▼
┌─────────────┐ ┌─────────────┐
│ DataStore │ │ 內存/靜態 │
│ (Token、 │ │ 當前用戶 │
│ UserId、 │ │ 對象 (單例) │
│ 自動登錄) │ │ │
└─────────────┘ └─────────────┘
// 依賴: implementation "androidx.datastore:datastore-preferences:1.0.0"
@Singleton
class UserPreferences @Inject constructor(
@ApplicationContext context: Context
) {
private val dataStore = context.createDataStore("user_prefs")
// Key 定義
private val TOKEN_KEY = stringPreferencesKey("auth_token")
private val USER_ID_KEY = longPreferencesKey("user_id")
private val AUTO_LOGIN_KEY = booleanPreferencesKey("auto_login")
// 異步保存 (協程)
suspend fun saveLoginResult(token: String, userId: Long, autoLogin: Boolean) {
dataStore.edit { preferences ->
preferences[TOKEN_KEY] = token
preferences[USER_ID_KEY] = userId
preferences[AUTO_LOGIN_KEY] = autoLogin
}
}
// Flow 觀察數據變化 (自動更新 UI)
val tokenFlow: Flow = dataStore.data.map { it[TOKEN_KEY] }
val userIdFlow: Flow = dataStore.data.map { it[USER_ID_KEY] }
val autoLoginFlow: Flow = dataStore.data.map { it[AUTO_LOGIN_KEY] ?: false }
}
// 使用
lifecycleScope.launch {
userPreferences.saveLoginResult("abc123", 1001, true)
}
// 觀察
userPreferences.tokenFlow.collect { token -> /* 更新 UI */ }
// 保存
SharedPreferences sp = getSharedPreferences("user_data", MODE_PRIVATE);
sp.edit()
.putString("token", "abc123")
.putLong("user_id", 1001)
.putBoolean("auto_login", true)
.apply(); // 異步提交,不阻塞主線程
// 讀取
String token = sp.getString("token", "");
long userId = sp.getLong("user_id", -1);
boolean autoLogin = sp.getBoolean("auto_login", false);
Android 開發**請忘記 Java 原生 IO 流** 存儲業務數據。
註冊/登錄憑證 → DataStore (新) / SharedPreferences (舊)
結構化業務數據 → Room (SQLite)
大文件/媒體 → 內部/外部存儲 (MediaStore/SAF)