首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計疑難解答

Android 數據存儲方案:SharedPreferences / 數據庫 / 文件存儲 選型指南,不建議直接用 Java IO 流

     編輯:程式設計疑難解答

直接回答

Android 可以使用 Java IO 流 (FileInputStream/OutputStream),但**強烈不建議**在註冊/登錄等業務場景直接手寫文件讀寫。Android 提供了更適合移動端的數據持久化機制。

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、   │  │  對象 (單例) │
│  自動登錄)  │  │             │
└─────────────┘  └─────────────┘

代碼示例:DataStore 存儲登錄狀態 (現代推薦)

// 依賴: 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 快速上手 (舊項目維護)

// 保存
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);

為什麼不建議手寫文件 IO 存用戶信息?

  1. 路徑管理麻煩:`getFilesDir()`、`getExternalFilesDir()`、分區存儲適配 (Android 10+)。
  2. 併發安全無保障:多進程/多線程讀寫同一文件極易損壞,需手動加鎖。
  3. 解析成本高:每次讀取需完整解析 JSON/文本,SharedPreferences/DataStore 內存映射極快。
  4. 安全性差:文件易被 Root 用戶或備份工具讀取,SharedPreferences 受沙箱保護 (可配合 EncryptedSharedPreferences 加密)。
  5. 維護地獄:字段增減需手動兼容舊版本文件格式,DataStore 自動處理遷移。

總結

Android 開發**請忘記 Java 原生 IO 流** 存儲業務數據。
註冊/登錄憑證 → DataStore (新) / SharedPreferences (舊)
結構化業務數據 → Room (SQLite)
大文件/媒體 → 內部/外部存儲 (MediaStore/SAF)

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved