在这里插入图片描述

在 Android 应用开发中,数据持久化是构建可靠、可恢复用户体验的基础能力。系统提供了多种存储方案,开发者需根据数据类型、访问频率、安全性和复杂度选择合适的方式。本文将深入讲解三种最常用的数据存储机制:

  1. 文件存储(File Storage):适用于原始文本或二进制数据;
  2. SharedPreferences:适用于轻量级键值对配置;
  3. SQLite 数据库:适用于结构化、关系型数据管理。

📌 核心原则

  • 简单数据 → SharedPreferences
  • 原始流/大文件 → 内部/外部文件存储
  • 结构化数据 → SQLite / Room

文件存储

文件存储是 Android 最基础的持久化方式,它将数据以原始字节流形式保存到设备文件系统中,不对内容做任何格式化处理。因此,它特别适合存储日志、缓存、图片、音频等二进制数据,或简单的文本记录。

存储位置分类

类型 路径 是否私有 是否需要权限
内部存储 /data/data/<package>/files/ ✅ 是 ❌ 否
外部存储(私有) /storage/emulated/0/Android/data/<package>/files/ ✅ 是(应用卸载自动删除) ❌ Android 10+ 不需要
外部存储(公共) /storage/emulated/0/Pictures/ ❌ 否 ✅ 需要 READ_EXTERNAL_STORAGE / WRITE_EXTERNAL_STORAGE

🔒 安全建议
敏感数据(如 token、用户信息)必须使用内部存储,避免被其他应用读取。

示例解析:内部文件读写

您提供的代码使用 openFileOutput()openFileInput() 操作内部私有文件

// 保存
val fos = openFileOutput("my_data.txt", MODE_PRIVATE)
fos.write(data.toByteArray())
fos.close()

// 读取
val fis = openFileInput("my_data.txt")
val content = fis.bufferedReader().use { it.readText() }

⚙️ 关键点

  • MODE_PRIVATE:仅本应用可访问;
  • 文件名 "my_data.txt" 无需带路径,系统自动存入内部目录;
  • 使用 BufferedReader 提升大文件读取效率;
  • 务必关闭流(推荐使用 use {} 自动管理资源)。
运行效果:
  • 输入文本并点击“保存数据” → 数据写入内部文件;
    在这里插入图片描述

  • 点击“加载数据” → 从文件读取并显示;
    在这里插入图片描述

🚫 局限性

  • 无法直接查询或更新部分内容;
  • 大量结构化数据需自行设计解析格式(如 JSON、CSV);
  • 不支持并发写入。

适用场景

  • 用户编辑的草稿;
  • 网络请求缓存;
  • 日志记录。

SharedPreferences 存储

SharedPreferences 是 Android 提供的轻量级键值对存储方案,底层基于 XML 文件实现,适合保存应用配置、用户偏好、登录状态等简单数据。

核心特性

  • 数据类型支持String, Int, Long, Float, Boolean, Set<String>
  • 线程安全:内部使用同步锁;
  • 自动序列化:无需手动解析;
  • 私有性:默认仅本应用可访问。

示例解析:保存用户信息

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

// 保存
val editor = sharedPrefs.edit()
editor.putString("name", "张三")
editor.putInt("age", 25)
editor.putLong("timestamp", System.currentTimeMillis())
editor.apply() // 异步提交(推荐)

// 读取
val name = sharedPrefs.getString("name", "") ?: ""
val age = sharedPrefs.getInt("age", 0)

🔑 apply() vs commit()

  • apply():异步写入磁盘,不阻塞主线程(推荐);
  • commit():同步写入,返回布尔值表示成功与否(慎用)。
布局与交互:
  • 输入姓名和年龄 → 点击“保存数据”;
    在这里插入图片描述

  • 点击“加载数据” → 显示完整信息(含时间戳);
    在这里插入图片描述

⚠️ 注意事项

  • 不要存储大量数据(如列表、对象),会导致 ANR;
  • 避免频繁写入(如每秒多次),影响性能;
  • 敏感信息需加密(如密码),可结合 EncryptedSharedPreferences(Jetpack Security 库)。

最佳实践

// 封装工具类
object UserPrefs {
    private const val PREF_NAME = "user_prefs"
    
    fun saveUserInfo(context: Context, name: String, age: Int) {
        context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE).edit {
            putString("name", name)
            putInt("age", age)
        }
    }
}

数据库(SQLite)

当数据具有结构化、关联性、需频繁查询/更新时,SQLite 是 Android 官方推荐的嵌入式关系型数据库。

为什么选择 SQLite?

  • 轻量高效:单文件数据库,无独立服务进程;
  • ACID 支持:保证数据一致性;
  • SQL 标准:支持复杂查询、索引、事务;
  • Android 深度集成:通过 SQLiteOpenHelper 管理。

📢 现代替代方案
Google 推荐使用 Room Persistence Library(Jetpack 组件),它在 SQLite 上提供编译时 SQL 验证、LiveData 支持、Kotlin 协程等高级功能。但理解原生 SQLite 仍是基础。

示例解析:书籍管理系统

您的代码展示了完整的 CRUD 操作:

1. 数据模型
data class Book(
    val id: Int = 0,
    val name: String,
    val author: String,
    val price: Double,
    val pages: Int
)
2. 数据库帮助类(MyDatabaseHelper)

继承 SQLiteOpenHelper,负责创建/升级表

class MyDatabaseHelper(context: Context, name: String, version: Int) 
    : SQLiteOpenHelper(context, name, null, version) {

    override fun onCreate(db: SQLiteDatabase) {
        db.execSQL("CREATE TABLE Book (id INTEGER PRIMARY KEY AUTOINCREMENT, ...)")
    }

    override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
        db.execSQL("DROP TABLE IF EXISTS Book")
        onCreate(db) // 简单粗暴,生产环境应做数据迁移
    }
}

⚠️ onUpgrade 警告
直接 DROP TABLE丢失所有用户数据!正式项目应使用 ALTER TABLE 或版本迁移脚本。

3. CRUD 操作封装
  • db.insert() → 返回新记录 ID;
  • db.delete() → 返回删除行数;
  • db.update() → 返回更新行数;
  • db.query() → 返回 Cursor,需遍历解析。
fun addBook(book: Book): Long {
    val db = writableDatabase
    val values = ContentValues().apply {
        put("name", book.name)
        put("author", book.author)
        // ...
    }
    return db.insert("Book", null, values).also { db.close() }
}

🔍 ContentValues 优势

  • 类型安全(避免 SQL 注入);
  • 自动转义特殊字符。
4. UI 交互
  • 添加书籍:输入书名、作者、价格、页数 → 点击“添加”;
    在这里插入图片描述

  • 删除书籍:输入 ID → 弹出确认对话框 → 执行删除;
    在这里插入图片描述

  • 更新书籍:输入 ID 及新信息 → 更新对应记录;
    在这里插入图片描述

  • 查询所有:加载并格式化显示全部书籍;
    在这里插入图片描述

高级查询示例(代码中已实现):

  • 按作者模糊查询:author LIKE '%关键词%'
  • 按价格范围筛选:price <= ?

三种存储方式对比总结

特性 文件存储 SharedPreferences SQLite
数据结构 无结构(原始字节) 键值对 表格(结构化)
查询能力 无(需全读解析) 按 Key 获取 强大(SQL)
性能 读写大文件快 小数据极快 中等(索引优化后快)
安全性 内部存储高 默认高 默认高
适用数据量 KB ~ MB < 1MB MB ~ GB
典型场景 日志、缓存、媒体文件 设置、Token、状态标志 用户资料、订单、消息

最佳实践与避坑指南

🛡️ 安全性

  • 敏感数据加密:使用 EncryptedSharedPreferencesJetpack Security
  • 避免外部存储明文:尤其 Android 10 以下需动态申请权限;
  • SQL 注入防护:永远使用 ? 占位符 + selectionArgs,而非字符串拼接。

⚡ 性能优化

  • SharedPreferences:避免在循环中频繁写入;
  • SQLite
    • 批量操作使用事务:db.beginTransaction()
    • 为常查询字段添加索引:CREATE INDEX idx_author ON Book(author);
  • 文件:大文件使用 BufferedInputStream/OutputStream

🧪 调试技巧

  • 查看 SharedPreferencesDevice File Explorer/data/data/<package>/shared_prefs/
  • 查看数据库:使用 Database Inspector(Android Studio 内置工具);
  • 日志输出:关键操作添加 Log.d() 便于追踪。

🔄 现代化建议

  • 优先使用 Jetpack 组件
    • DataStore 替代 SharedPreferences(支持协程、类型安全);
    • Room 替代原生 SQLite(减少样板代码,提升可维护性)。

结语

掌握 文件、SharedPreferences、SQLite 三大存储方式,是 Android 开发者的必备技能。它们各有适用边界,合理选择能显著提升应用的性能、安全与用户体验

💡 终极建议

  • 简单配置 → DataStore
  • 结构化数据 → Room
  • 原始文件 → 内部存储 + 加密。

通过本文的实战代码与深度解析,相信你已具备在真实项目中灵活运用数据持久化技术的能力。

Logo

助力广东及东莞地区开发者,代码托管、在线学习与竞赛、技术交流与分享、资源共享、职业发展,成为松山湖开发者首选的工作与学习平台

更多推荐