Jorgen's blog Jorgen's blog
首页
  • 平台架构
  • 混合式开发记录
  • 推送服务
  • 数据分析
  • 实时调度
  • 架构思想

    • 分布式
  • 编程框架工具

    • 编程语言
    • 框架
    • 开发工具
  • 数据存储与处理

    • 数据库
    • 大数据
  • 消息、缓存与搜索

    • 消息队列
    • 搜索与日志分析
  • 前端与跨端开发

    • 前端技术
    • Android
  • 系统与运维

    • 操作系统
    • 容器化与 DevOps
  • 物联网与安全

    • 通信协议
    • 安全
    • 云平台
newland
  • 关于我
  • 终身学习
  • 关于时间的感悟
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

jorgen

Love it, make mistakes, learn, keep grinding.
首页
  • 平台架构
  • 混合式开发记录
  • 推送服务
  • 数据分析
  • 实时调度
  • 架构思想

    • 分布式
  • 编程框架工具

    • 编程语言
    • 框架
    • 开发工具
  • 数据存储与处理

    • 数据库
    • 大数据
  • 消息、缓存与搜索

    • 消息队列
    • 搜索与日志分析
  • 前端与跨端开发

    • 前端技术
    • Android
  • 系统与运维

    • 操作系统
    • 容器化与 DevOps
  • 物联网与安全

    • 通信协议
    • 安全
    • 云平台
newland
  • 关于我
  • 终身学习
  • 关于时间的感悟
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • Capacitor浅析
  • ADB调试
  • mlkit
  • face detection
  • Android中的Kotlin协程:告别回调地狱
  • Android性能优化实践与技巧
  • Android Jetpack Compose入门:构建现代UI的全新方式
  • Android Jetpack Compose入门与实践 - 构建现代Android UI
  • Android Jetpack Compose入门指南 - 构建现代UI的全新方式
  • Android Jetpack与架构组件-构建现代化应用
  • Android Jetpack架构组件:ViewModel与LiveData实战指南
  • Android Jetpack组件:构建现代Android应用的核心利器
  • Android Jetpack组件详解:构建现代化应用的核心
  • Android数据绑定与MVVM架构-构建现代化应用
  • Android架构组件:构建现代化应用的基石
  • Android架构组件与Jetpack-构建现代化应用的基石
  • Android架构组件与Jetpack-构建现代化应用的基础
  • Android架构设计之MVVM模式实战指南
  • 拥抱未来:Android Jetpack Compose入门指南
  • Android权限管理完全指南-从基础到实践
  • Android测试指南-从单元测试到UI测试的实践之路
  • Android依赖注入实战:从Dagger到Hilt的进化之路
  • Android网络编程完全指南-从HTTP到Retrofit的实践之路
  • Android数据持久化完全指南-从SharedPreferences到Room数据库
    • 前言
    • Android数据持久化概述
      • 数据持久化的主要方式
    • SharedPreferences详解
      • 基本用法
      • SharedPreferences的优缺点
    • SQLite数据库与Room持久化库
      • Room基础架构
      • 实现步骤
      • 1. 添加依赖
      • 2. 定义Entity
      • 3. 创建DAO
      • 4. 创建Database
      • 5. 使用Room数据库
      • Room的高级特性
      • 1. 数据迁移
      • 2. 类型转换器
    • 其他数据持久化方式
      • 内部存储与外部存储
      • 内部存储
      • 外部存储
      • 内容提供者(ContentProvider)
    • 数据持久化方案选择指南
      • 数据量与复杂度
      • 性能考虑
      • 安全性考虑
    • 实战案例:构建完整的数据持久化方案
      • 场景描述
      • 数据持久化方案设计
      • 实现步骤
      • 1. 定义数据模型
      • 2. 实现数据访问层
      • 3. 实现文件存储管理
      • 4. 仓库模式实现
    • 结语
  • Android多线程与并发处理完全指南-从Thread到协程的进阶之路
  • Android应用打包与发布全流程指南-从签名到上架的实战之路
  • Android安全完全指南-从基础防护到高级加密的实战之路
  • android
Jorgen
2026-01-28
目录

Android数据持久化完全指南-从SharedPreferences到Room数据库

# 前言

大家好!我是Jorgen,今天想和大家聊一聊Android开发中一个非常重要但又经常被忽视的话题——数据持久化。🤔

在开发Android应用时,我们经常需要保存用户数据、应用配置或缓存信息。从简单的键值对存储到复杂的数据库操作,Android提供了多种数据持久化方案。但面对这么多选择,你是否也曾感到困惑:什么时候该用SharedPreferences?什么时候又该选择Room数据库?今天,我将带大家全面了解Android中的数据持久化方案,帮助你在实际开发中做出最佳选择。

提示

数据持久化是构建健壮Android应用的基础,合理选择存储方案不仅能提升用户体验,还能优化应用性能。

# Android数据持久化概述

在Android中,数据持久化指的是将数据保存到设备存储中,使得即使应用关闭或设备重启,数据仍然可以被访问。Android提供了多种数据持久化方式,每种方式都有其适用场景和优缺点。

# 数据持久化的主要方式

  1. SharedPreferences:轻量级的键值对存储
  2. 内部存储:应用私有文件存储
  3. 外部存储:共享文件存储
  4. SQLite数据库:关系型数据库存储
  5. Room持久化库:SQLite的抽象层
  6. 内容提供者(ContentProvider):数据共享机制
  7. 网络存储:云端数据存储

# SharedPreferences详解

SharedPreferences是Android中最简单的数据持久化方式,适用于存储少量简单的键值对数据。

# 基本用法

// 获取SharedPreferences实例
val sharedPreferences = getSharedPreferences("my_app_prefs", Context.MODE_PRIVATE)

// 存储数据
val editor = sharedPreferences.edit()
editor.putString("username", "Jorgen")
editor.putInt("age", 25)
editor.putBoolean("is_logged_in", true)
editor.apply() // 异步提交

// 读取数据
val username = sharedPreferences.getString("username", "")
val age = sharedPreferences.getInt("age", 0)
val isLoggedIn = sharedPreferences.getBoolean("is_logged_in", false)
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# SharedPreferences的优缺点

优点 缺点
使用简单,API直观 不适合存储大量数据
支持多种基本数据类型 不支持复杂查询
自动处理线程安全 不适合存储结构化数据
适合存储用户设置和偏好 不适合存储敏感信息

THEOREM

最佳实践:SharedPreferences适合存储应用配置、用户偏好设置等少量简单数据,不适合存储大量或复杂的数据结构。

# SQLite数据库与Room持久化库

当需要存储结构化数据时,SQLite是Android中的标准选择。而Room是Google提供的持久化库,它是对SQLite的抽象层,提供了更便捷的数据访问方式。

# Room基础架构

Room主要由三个组件组成:

  1. Entity:数据库表
  2. DAO:数据访问对象
  3. Database:数据库持有者

# 实现步骤

# 1. 添加依赖

// build.gradle (Module: app)
dependencies {
    def room_version = "2.6.1"
    
    implementation "androidx.room:room-runtime:$room_version"
    kapt "androidx.room:room-compiler:$room_version"
    
    // Kotlin Extensions and Coroutines support for Room
    implementation "androidx.room:room-ktx:$room_version"
}
1
2
3
4
5
6
7
8
9
10

# 2. 定义Entity

@Entity(tableName = "users")
data class User(
    @PrimaryKey(autoGenerate = true) val id: Int = 0,
    @ColumnInfo(name = "name") val name: String,
    @ColumnInfo(name = "email") val email: String,
    @ColumnInfo(name = "age") val age: Int
)
1
2
3
4
5
6
7

# 3. 创建DAO

@Dao
interface UserDao {
    @Insert
    suspend fun insert(user: User): Long

    @Query("SELECT * FROM users")
    fun getAllUsers(): Flow<List<User>>

    @Query("SELECT * FROM users WHERE id = :userId")
    suspend fun getUserById(userId: Int): User?

    @Update
    suspend fun update(user: User)

    @Delete
    suspend fun delete(user: User)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 4. 创建Database

@Database(entities = [User::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
    abstract fun userDao(): UserDao
    
    companion object {
        @Volatile
        private var INSTANCE: AppDatabase? = null
        
        fun getDatabase(context: Context): AppDatabase {
            return INSTANCE ?: synchronized(this) {
                val instance = Room.databaseBuilder(
                    context.applicationContext,
                    AppDatabase::class.java,
                    "app_database"
                ).build()
                INSTANCE = instance
                instance
            }
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 5. 使用Room数据库

class UserRepository(private val userDao: UserDao) {
    val allUsers: Flow<List<User>> = userDao.getAllUsers()
    
    suspend fun insert(user: User) {
        userDao.insert(user)
    }
    
    // 其他数据库操作...
}

// 在ViewModel中使用
class UserViewModel(application: Application) : AndroidViewModel(application) {
    private val repository: UserRepository
    val allUsers: Flow<List<User>>
    
    init {
        val userDao = AppDatabase.getDatabase(application).userDao()
        repository = UserRepository(userDao)
        allUsers = repository.allUsers
    }
    
    fun insertUser(name: String, email: String, age: Int) {
        viewModelScope.launch {
            val user = User(name = name, email = email, age = age)
            repository.insert(user)
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

# Room的高级特性

# 1. 数据迁移

@Database(entities = [User::class], version = 2)
abstract class AppDatabase : RoomDatabase() {
    // ...
}

// 创建Migration类
val MIGRATION_1_2 = object : Migration(1, 2) {
    override fun migrate(database: SupportSQLiteDatabase) {
        // 执行数据库迁移逻辑
        database.execSQL("ALTER TABLE users ADD COLUMN phone TEXT")
    }
}

// 在Database构建时应用迁移
val db = Room.databaseBuilder(
    context.applicationContext,
    AppDatabase::class.java, "database-name"
)
    .addMigrations(MIGRATION_1_2)
    .build()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 2. 类型转换器

class Converters {
    @TypeConverter
    fun fromTimestamp(value: Long?): Date? {
        return value?.let { Date(it) }
    }

    @TypeConverter
    fun dateToTimestamp(date: Date?): Long? {
        return date?.time
    }
}

// 在Database类中应用转换器
@Database(entities = [User::class], version = 1)
@TypeConverters(Converters::class)
abstract class AppDatabase : RoomDatabase() {
    // ...
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

"Room不仅简化了数据库操作,还提供了编译时SQL验证,大大减少了运行时错误。"

# 其他数据持久化方式

# 内部存储与外部存储

# 内部存储

// 保存文件
val file = File(context.filesDir, "my_file.txt")
file.writeText("Hello, Android!")

// 读取文件
val content = File(context.filesDir, "my_file.txt").readText()
1
2
3
4
5
6

# 外部存储

// 检查外部存储权限
if (ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) 
    != PackageManager.PERMISSION_GRANTED) {
    // 请求权限
}

// 保存文件到外部存储
val externalDir = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES)
val file = File(externalDir, "my_image.jpg")
file.writeBytes(imageBytes)
1
2
3
4
5
6
7
8
9
10

# 内容提供者(ContentProvider)

内容提供者允许应用将数据共享给其他应用,是Android中实现数据共享的标准方式。

// 定义内容提供者
class UserProvider : ContentProvider() {
    override fun query(uri: Uri, projection: Array<String>?, selection: String?,
                       selectionArgs: Array<String>?, sortOrder: String?): Cursor? {
        // 实现查询逻辑
    }
    
    override fun insert(uri: Uri, values: ContentValues?): Uri? {
        // 实现插入逻辑
    }
    
    override fun update(uri: Uri, values: ContentValues?, selection: String?,
                       selectionArgs: Array<String>?): Int {
        // 实现更新逻辑
    }
    
    override fun delete(uri: Uri, selection: String?, selectionArgs: Array<String>?): Int {
        // 实现删除逻辑
    }
    
    override fun getType(uri: Uri): String? {
        // 返回MIME类型
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# 数据持久化方案选择指南

面对多种数据持久化方案,如何做出最佳选择?下面是一个简单的决策指南:

# 数据量与复杂度

数据量 数据复杂度 推荐方案
少量 简单键值对 SharedPreferences
中等 结构化数据 Room数据库
大量 复杂数据关系 Room数据库+索引优化
文件 图片、音频等 内部/外部存储
需要共享 跨应用数据 ContentProvider

# 性能考虑

  • 读取速度:内存 > SharedPreferences > Room > 文件存储
  • 写入速度:SharedPreferences > 内存 > Room > 文件存储
  • 查询能力:Room > 文件存储 > SharedPreferences

# 安全性考虑

  • 敏感数据:使用加密存储,如EncryptedSharedPreferences
  • 用户隐私:遵循最小权限原则,避免不必要的数据收集

提示

在实际开发中,常常需要组合使用多种数据持久化方案,以满足不同的业务需求。

# 实战案例:构建完整的数据持久化方案

让我们通过一个实际案例,展示如何构建一个完整的数据持久化方案。

# 场景描述

假设我们要开发一个笔记应用,需要存储以下数据:

  1. 用户设置(主题、字体大小等)
  2. 笔记列表(标题、创建时间等)
  3. 笔记内容(富文本内容)
  4. 笔记附件(图片、音频等)

# 数据持久化方案设计

数据类型 存储方案 理由
用户设置 SharedPreferences 少量键值对,需要快速访问
笔记列表 Room数据库 结构化数据,需要查询和排序
笔记内容 Room数据库 + 文件存储 富文本内容较大,部分存储在文件中
笔记附件 外部存储 文件较大,需要独立管理

# 实现步骤

# 1. 定义数据模型

@Entity(tableName = "note_settings")
data class NoteSettings(
    @PrimaryKey val id: Int = 0,
    @ColumnInfo(name = "theme") val theme: String = "light",
    @ColumnInfo(name = "font_size") val fontSize: Int = 16,
    @ColumnInfo(name = "auto_save") val autoSave: Boolean = true
)

@Entity(tableName = "notes")
data class Note(
    @PrimaryKey(autoGenerate = true) val id: Int = 0,
    @ColumnInfo(name = "title") val title: String,
    @ColumnInfo(name = "content") val content: String,
    @ColumnInfo(name = "created_at") val createdAt: Long = System.currentTimeMillis(),
    @ColumnInfo(name = "updated_at") val updatedAt: Long = System.currentTimeMillis(),
    @ColumnInfo(name = "has_attachments") val hasAttachments: Boolean = false
)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 2. 实现数据访问层

@Dao
interface NoteSettingsDao {
    @Query("SELECT * FROM note_settings WHERE id = 0")
    suspend fun getSettings(): NoteSettings
    
    @Update
    suspend fun updateSettings(settings: NoteSettings)
}

@Dao
interface NoteDao {
    @Insert
    suspend fun insert(note: Note): Long
    
    @Query("SELECT * FROM notes ORDER BY updated_at DESC")
    fun getAllNotes(): Flow<List<Note>>
    
    @Query("SELECT * FROM notes WHERE id = :noteId")
    suspend fun getNoteById(noteId: Int): Note?
    
    @Update
    suspend fun update(note: Note)
    
    @Delete
    suspend fun delete(note: Note)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

# 3. 实现文件存储管理

class NoteFileManager(private val context: Context) {
    private val notesDir = File(context.filesDir, "notes")
    
    init {
        if (!notesDir.exists()) {
            notesDir.mkdirs()
        }
    }
    
    fun saveNoteContent(noteId: Int, content: String) {
        val file = File(notesDir, "note_$noteId.txt")
        file.writeText(content)
    }
    
    fun getNoteContent(noteId: Int): String {
        val file = File(notesDir, "note_$noteId.txt")
        return if (file.exists()) file.readText() else ""
    }
    
    fun saveAttachment(noteId: Int, fileName: String, bytes: ByteArray) {
        val attachmentDir = File(notesDir, "note_$noteId")
        if (!attachmentDir.exists()) {
            attachmentDir.mkdirs()
        }
        val file = File(attachmentDir, fileName)
        file.writeBytes(bytes)
    }
    
    fun getAttachmentPath(noteId: Int, fileName: String): String {
        return File(notesDir, "note_$noteId", fileName).absolutePath
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

# 4. 仓库模式实现

class NoteRepository(
    private val noteSettingsDao: NoteSettingsDao,
    private val noteDao: NoteDao,
    private val fileManager: NoteFileManager
) {
    val allNotes: Flow<List<Note>> = noteDao.getAllNotes()
    
    suspend fun getSettings(): NoteSettings {
        return noteSettingsDao.getSettings()
    }
    
    suspend fun updateSettings(settings: NoteSettings) {
        noteSettingsDao.updateSettings(settings)
    }
    
    suspend fun saveNote(note: Note, content: String): Long {
        val noteId = if (note.id == 0) {
            noteDao.insert(note)
        } else {
            noteDao.update(note)
            note.id
        }
        
        // 保存笔记内容到文件
        fileManager.saveNoteContent(noteId.toInt(), content)
        
        return noteId.toLong()
    }
    
    suspend fun getNoteWithContent(noteId: Int): Pair<Note, String> {
        val note = noteDao.getNoteById(noteId) ?: throw Exception("Note not found")
        val content = fileManager.getNoteContent(noteId)
        return Pair(note, content)
    }
    
    // 其他方法...
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

# 结语

通过今天的分享,我们全面了解了Android中的数据持久化方案,从简单的SharedPreferences到复杂的Room数据库,以及文件存储和内容提供者。🎉

在实际开发中,没有一种存储方案是万能的,我们需要根据具体需求选择最合适的方案,或者组合使用多种方案。记住以下关键原则:

  1. 简单数据用SharedPreferences:适合存储配置和少量键值对
  2. 结构化数据用Room:提供类型安全、编译时检查和强大的查询能力
  3. 大文件用文件存储:图片、音频等大文件应使用文件系统存储
  4. 跨应用共享用ContentProvider:需要与其他应用共享数据时使用

合理的数据持久化设计不仅能提升应用性能,还能改善用户体验。希望今天的分享对你有所帮助!如果你有任何问题或建议,欢迎在评论区留言交流。😊

数据持久化是Android开发的基础技能,掌握它将帮助你构建更稳定、更高效的应用。记住,选择合适的存储方案,就像选择合适的工具一样重要。


感谢阅读!如果觉得这篇文章对你有帮助,别忘了点赞和关注哦!👍

#Android开发#数据存储#Room数据库
上次更新: 2026/01/28, 14:00:21
Android网络编程完全指南-从HTTP到Retrofit的实践之路
Android多线程与并发处理完全指南-从Thread到协程的进阶之路

← Android网络编程完全指南-从HTTP到Retrofit的实践之路 Android多线程与并发处理完全指南-从Thread到协程的进阶之路→

最近更新
01
LLM
01-30
02
intro
01-30
03
intro
01-30
更多文章>
Theme by Vdoing | Copyright © 2019-2026 Jorgen | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式