当前位置: 首页 > news >正文

肝货!Android 持久化技术全解:SharedPreference + 文件存储实战一本通

肝货!Android 持久化技术全解:SharedPreference + 文件存储实战一本通


目录

  1. 什么是持久化?
  2. Android 持久化方式一览
  3. SharedPreference 详解
  4. 文件存储详解
  5. 内部存储 vs 外部存储
  6. 实战代码演示
  7. 注意事项与最佳实践

1. 什么是持久化?

概念

持久化是将数据存储到非易失性存储(断电后数据不丢失)中。

内存(易失性):程序运行时使用,断电丢失 ↓ 持久化 磁盘(非易失性):数据永久保存

手机关机再开机后,数据还在 → 持久化成功


2. Android 持久化方式一览

方式适用场景数据量速度
SharedPreference键值对、设置项
文件存储文本、大数据较慢
SQLite 数据库结构化数据大量
Room复杂查询大量快(封装后)
ContentProvider数据共享不限
DataStore替代 SharedPreference小-中

3. SharedPreference 详解

3.1 什么是 SharedPreference?

用于存储键值对数据的轻量级存储方式,适合保存配置、状态等小数据。

3.2 基本使用

// 获取 SharedPreference 对象valprefs=getSharedPreferences("my_prefs",Context.MODE_PRIVATE)// 保存数据prefs.edit().apply{putString("username","张三")putInt("age",25)putBoolean("isLogin",true)apply()// 异步保存// 或 commit() 同步保存,返回 boolean}// 读取数据valusername=prefs.getString("username","默认值")valage=prefs.getInt("age",0)valisLogin=prefs.getBoolean("isLogin",false)

3.3 两种获取方式

// 方式1:指定名称(一个应用可以有多个 Prefs 文件)valprefs1=getSharedPreferences("user_prefs",Context.MODE_PRIVATE)valprefs2=getSharedPreferences("app_settings",Context.MODE_PRIVATE)// 方式2:Activity 私有(自动使用 Activity 名称作为文件名)valprefs=getPreferences(Context.MODE_PRIVATE)

3.4 MODE modes(存储模式)

模式说明
MODE_PRIVATE只有本应用可访问(最常用
MODE_WORLD_READABLE其他应用可读(已废弃
MODE_WORLD_WRITABLE其他应用可写(已废弃
MODE_MULTI_PROCESS多进程访问(不推荐)

3.5 apply vs commit

对比apply()commit()
返回值voidboolean(是否成功)
执行方式异步同步
性能更快稍慢
安全性丢失的机会更小写入更安全

推荐:大多数情况用apply(),如果需要知道写入结果再用commit()


4. 文件存储详解

4.1 内部存储

文件存储在应用私有目录下,其他应用无法访问。

// 保存到内部存储valcontent="Hello World"valfileName="test.txt"valfos=openFileOutput(fileName,Context.MODE_PRIVATE)fos.write(content.toByteArray())fos.close()// 读取内部存储valfis=openFileInput(fileName)valbytes=ByteArray(fis.available())fis.read(bytes)fis.close()valcontent=String(bytes)

4.2 内部存储目录

// 获取各种目录filesDir// /data/data/<package>/filescacheDir// /data/data/<package>/cachefilesDir.path// 查看路径// 文件操作valfile=File(filesDir,"test.txt")file.writeText("Hello")valcontent=file.readText()

4.3 外部存储

需要权限,且可能不可用(SD 卡拔出、存储满)。

// 外部存储路径valexternalFilesDir=getExternalFilesDir(null)// /storage/emulated/0/Android/data/<package>/files// 检查外部存储是否可用funisExternalStorageWritable():Boolean{returnEnvironment.getExternalStorageState()==Environment.MEDIA_MOUNTED}

4.4 权限说明

<!-- Android 10+ 外部存储需要权限(部分场景)--><uses-permissionandroid:name="android.permission.WRITE_EXTERNAL_STORAGE"/><uses-permissionandroid:name="android.permission.READ_EXTERNAL_STORAGE"/><!-- Android 13+ 使用 MediaStore API 访问媒体文件 -->

5. 内部存储 vs 外部存储

对比内部存储外部存储
路径/data/data/<package>/files//storage/.../Android/data/<package>/files/
访问权限本应用私有,其他应用不可访问可被其他应用读取
卸载应用数据被删除Android 10+ 部分被删除
容量有限,但有保证受限于设备存储空间
速度较快较慢
需要权限不需要需要(某些场景)

6. 实战代码演示

6.1 SharedPreference 完整示例

classPersistenceActivity:AppCompatActivity(){companionobject{constvalPREFS_NAME="my_prefs"constvalKEY_USERNAME="username"constvalKEY_PASSWORD="password"}privatelateinitvaretUsername:EditTextprivatelateinitvaretPassword:EditTextoverridefunonCreate(savedInstanceState:Bundle?){super.onCreate(savedInstanceState)setContentView(R.layout.activity_persistence)// 保存数据funsaveToSharedPreference(){valusername=etUsername.text.toString()valpassword=etPassword.text.toString()valprefs=getSharedPreferences(PREFS_NAME,Context.MODE_PRIVATE)prefs.edit().apply{putString(KEY_USERNAME,username)putString(KEY_PASSWORD,password)apply()}}// 读取数据funloadFromSharedPreference(){valprefs=getSharedPreferences(PREFS_NAME,Context.MODE_PRIVATE)valusername=prefs.getString(KEY_USERNAME,"未设置")valpassword=prefs.getString(KEY_PASSWORD,"未设置")tvResult.text="用户名:$username\n密码:$password"}}}

6.2 文件存储完整示例

companionobject{constvalFILE_NAME="user_data.txt"}// 保存到文件privatefunsaveToFile(username:String,password:String){valcontent="用户名:$username\n密码:$password"try{valfos=openFileOutput(FILE_NAME,Context.MODE_PRIVATE)fos.write(content.toByteArray())fos.close()Toast.makeText(this,"文件保存成功",Toast.LENGTH_SHORT).show()}catch(e:Exception){e.printStackTrace()Toast.makeText(this,"保存失败:${e.message}",Toast.LENGTH_SHORT).show()}}// 从文件读取privatefunloadFromFile():String{returntry{valfile=File(filesDir,FILE_NAME)if(!file.exists())return"文件不存在"file.readText()}catch(e:Exception){"读取失败:${e.message}"}}// 删除文件privatefundeleteFile(){valfile=File(filesDir,FILE_NAME)if(file.exists()){file.delete()}}

6.3 工具类封装(推荐)

objectPrefsManager{privateconstvalNAME="app_prefs"funsaveUser(context:Context,username:String,token:String){context.getSharedPreferences(NAME,Context.MODE_PRIVATE).edit().apply{putString("username",username)putString("token",token)apply()}}fungetUser(context:Context):Pair<String,String>{valprefs=context.getSharedPreferences(NAME,Context.MODE_PRIVATE)returnPair(prefs.getString("username","")?:"",prefs.getString("token","")?:"")}funclearUser(context:Context){context.getSharedPreferences(NAME,Context.MODE_PRIVATE).edit().clear().apply()}funisLoggedIn(context:Context):Boolean{valprefs=context.getSharedPreferences(NAME,Context.MODE_PRIVATE)returnprefs.getString("token","").isNotEmpty()}}

7. 注意事项与最佳实践

7.1 SharedPreference 注意事项

⚠️ 不要存储大量数据( > 1MB) ⚠️ 不要存储敏感信息(Token 等),加密后存储 ⚠️ MODE_MULTI_PROCESS 不推荐,线程不安全 ⚠️ 频繁修改同一个 key 性能差

优化建议

// ❌ 错误:频繁修改repeat(100){prefs.edit().putInt("count",it).apply()}// ✅ 正确:批量修改prefs.edit().apply{repeat(100){putInt("count_$it",it)}}

7.2 文件存储注意事项

⚠️ 外部存储需要权限 ⚠️ 存储前检查空间是否足够 ⚠️ 大文件使用缓冲流 ⚠️ 操作在后台线程执行

7.3 数据安全建议

// 如果必须存储敏感信息,使用 EncryptedSharedPreferencevalmasterKey=MasterKey.Builder(context).setKeyScheme(MasterKey.KeyScheme.AES256_GCM).build()valprefs=EncryptedSharedPreferences.create(context,"secure_prefs",masterKey,EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM)

7.4 选择存储方式

场景推荐方式
用户设置、登录状态SharedPreference
简单文本数据文件存储
结构化数据Room/SQLite
大量数据Room
跨应用共享ContentProvider
替代 SharedPreferenceDataStore

总结

  1. 持久化是将数据保存到磁盘,断电后不丢失
  2. SharedPreference适合存储键值对(设置、登录状态)
  3. 文件存储适合存储大量文本或二进制数据
  4. 内部存储本应用私有,不需要权限
  5. 外部存储需要权限,可被其他应用访问
  6. 安全:敏感信息用 EncryptedSharedPreference 或加密
http://www.jsqmd.com/news/682266/

相关文章:

  • nli-MiniLM2-L6-H768开源大模型部署教程:免配置镜像快速启用NLI服务
  • MathNet:全球数学推理与检索的多模态基准
  • vDisk课表联动功能技术文档说明
  • 2026最新:Windows安装 ComfyUI全攻略,快速配置Nano Banana Pro 模型实现批量生图自由
  • 杭州邹氏建设服务:临平区废旧物资回收公司 - LYL仔仔
  • 机器学习模型选择指南:从原理到实践
  • 【C# .NET 11 AI推理加速终极指南】:20年微软MVP亲授生产环境实测的7大GPU/CPU协同优化策略
  • 避坑指南:海康相机+OpenCVSharp4.x版本图像转换的正确姿势(从MV_DISPLAY_FRAME_INFO到Mat)
  • 大学生论文查重实用工具综合测评
  • 【Java Loom响应式转型实战手册】:20年架构师亲授3大避坑指南与5个高并发落地案例
  • TMS320C28x DSP编程避坑指南:从ACC到XT,那些手册里没细说的寄存器使用细节
  • egergergeeert部署教程:/root/ai-models路径下底座与LoRA模型组织规范
  • 杭州邹氏建设服务:临平区废旧物资回收电话 - LYL仔仔
  • 福禄一卡通回收新行情,回收平台哪家值得推荐 - 猎卡回收公众号
  • ReadCat:免费开源的终极小说阅读器,重新定义纯净阅读体验
  • 告别调参玄学:用Python手把手实现MOPSO,搞定多目标优化难题
  • Python-pptx实战:从数据到演示文稿的自动化生成
  • 10分钟终极指南:用F3D极简3D查看器快速可视化你的三维数据
  • 支付宝立减金怎么回收?快速找到最可靠的线上平台! - 团团收购物卡回收
  • 3个步骤让Windows 11界面重回经典:ExplorerPatcher全面解析
  • CubeIDE高版本封杀DAP-LINK?别慌,手把手教你用OpenOCD+GDB曲线救国(STM32F4实测)
  • nli-MiniLM2-L6-H768惊艳呈现:Web界面交互式NLI判断全过程演示
  • 胡桃工具箱终极指南:免费开源原神助手提升游戏体验的完整教程
  • 2026年广西仿石漆外墙定制与全屋整装完全指南:小木舟装饰官方联系电话与竞品深度横评 - 年度推荐企业名录
  • 深入解析JKSM:3DS游戏存档管理的核心原理与高效备份技巧
  • egergergeeert提示词工程:如何用‘elegant dress+silver hair’强化角色辨识度
  • 2026年厦门生成式引擎优化(GEO)领域3家主流服务机构综合能力分析 - 商业小白条
  • 斯玛特杉德卡回收亲测平台,回收不踩雷 - 猎卡回收公众号
  • OpenClaw在windows上部署
  • 别再死记硬背了!用动画图解二叉排序树的插入与删除(附C++代码调试技巧)