概述

在Android开发中,存储(Storage)的方式根据具体的需求不同而不同,例如数据对应用程序是私有的还是其他应用程序(和用户)可以访问的,以及保存数据需要多大的空间。

存储分类

主要的存储方式有以下几种(本文主要涉及前三种):

  1. Shared Preferences:以键值对( key-value pairs)的方式存储在程序内部;
  2. Internal Storage:将数据保存在设备内存中;
  3. External Storage:将公有数据保存在外部存储中(SD卡);
  4. SQLite Databases:保存结构化数据到私有数据库中;
  5. Network Connection:通过网络服务器,将数据存储在web上。

涉及知识点

涉及的知识点如下:

  1. SharedPreferences 共享目录接口,通过Context中的getSharedPreferences进行实例化。
  2. SharedPreferences.Editor 共享目录编辑器,需要以commit进行保存。
  3. FileOutputStream 文件输出流,用write方法将数据保存文件。
  4. FileInputStream 文件输入流,用于读取文件的内容,通过Context中的openFileInput进行实例化,用read方法进行读取内容。
  5. deleteFile Context中的方法,删除指定路径的文件
  6. Environment.getExternalStorageDirectory() 获取外部存储的根目录。
  7. Environment.getExternalStorageState() 获取外部存储卡的状态。
  8. File.separator 文件路径分割符,用斜杠(/)进行表示。
  9. BitmapFactory.decodeResource(getResources(), R.drawable.bg) 通过资源文件实例化对象。
  10. BitmapFactory.decodeFile(imgFile.getAbsolutePath() 通过具体文件的路径实例化对象。
  11. File 文件对象,mkdirs() 创建多层目录 mkdirs创建单个目录,exists() 判断文件或目录是否存在,createNewFile() 创建新文件。

Shared Preferences

此种方式,只能保存简单的数据类型如下图所示:

代码如下:

     /**
* SharedPreferences保存
* @param v
*/
public void sharedSave(View v){
String name=etName.getText().toString().trim();
String age=etAge.getText().toString().trim();
if(TextUtils.isEmpty(name)||TextUtils.isEmpty(age)){
return;
}
//构造一个编辑器----笔
SharedPreferences.Editor editor = sp.edit();
//数据的存储---只能存储简单的数据
editor.putString("name",name);
editor.putString("age",age);
//提交--保存
editor.commit();
//清空
etName.setText("");
etAge.setText("");
} /**
* SharedPreferences读取
*/
public void sharedRedo(View v){
String name=sp.getString("name","");
String age=sp.getString("age","");
etName.setText(name);
etAge.setText(age);
}

Internal Storage

将数据内容转换为字节的方式保存在文件中,如下图所示:

代码如下:

     /**
* 内部保存
* @param v
*/
public void internalSave(View v) {
String name = etName.getText().toString().trim();
String age = etAge.getText().toString().trim();
if (TextUtils.isEmpty(name) || TextUtils.isEmpty(age)) {
return;
} try {
String content = "这是我的姓名:" + name + "这是我的年龄:" + age;
FileOutputStream fos = openFileOutput(sname, MODE_PRIVATE);
fos.write(content.getBytes());
fos.close();
etName.setText("");
etAge.setText("");
} catch (IOException e) {
e.printStackTrace();
}
} /**
* 内部读取
* @param v
*/
public void internalRedo(View v) {
try {
FileInputStream fis = openFileInput(sname);
byte[] buffer = new byte[fis.available()];
fis.read(buffer);
fis.close();
String content = new String(buffer);
Toast.makeText(this, content, Toast.LENGTH_SHORT).show();
} catch (IOException e) {
e.printStackTrace();
}
} /**
* 删除文件
* @param v
*/
public void internalDel(View v){
boolean del=deleteFile(sname);
if(del){
Toast.makeText(this, "删除成功", Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(this, "删除失败", Toast.LENGTH_SHORT).show();
}
}

External Storage

在外部存储中,需要在AndroidManifest.xml中配置相关的读写权限,如下所示:

   <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"  />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />

保存在SD卡中,如下图所示:

代码如下:

     /**
* 外部存储
* @param v
*/
public void externalSave(View v) { try {
Log.i(TAG, "externalSave: 开始");
Bitmap img = BitmapFactory.decodeResource(getResources(), R.drawable.bg);
ByteArrayOutputStream bass = new ByteArrayOutputStream();
img.compress(Bitmap.CompressFormat.JPEG, 100, bass);
img.recycle();
Log.i(TAG, "externalSave: saveImg");
boolean saveOk = saveImg("dog.jpg", bass.toByteArray());
Log.i(TAG, "externalSave: saveImg:"+saveOk);
if (saveOk) {
Toast.makeText(this, "保存成功", Toast.LENGTH_SHORT).show();
}
bass.close();
Log.i(TAG, "externalSave: 结束");
} catch (IOException e) {
e.printStackTrace();
Log.i(TAG, "externalSave: 异常"+e.getMessage());
}
} /**
* 外部读取
* @param v
*/
public void externalRedo(View v) {
if (!isMounted()) {
return;
}
try {
Bitmap img = readImg("dog.jpg");
iv01.setImageBitmap(img);
} catch (Exception e) {
e.printStackTrace();
}
} private boolean saveImg(String fileName,byte[] data){
Log.i(TAG, "saveImg: 开始");
if(!isMounted()){
Log.i(TAG, "saveImg: 挂载失败");
return false;
}
Log.i(TAG, "saveImg: 路径:"+storedPath);
File dir=new File(storedPath);
if(!dir.exists()){
boolean f= dir.mkdirs();
if(f){
Log.i(TAG, "saveImg: 创建目录成功:"+storedPath);
}else{
Log.i(TAG, "saveImg: 创建目录失败:"+storedPath);
}
}
Log.i(TAG, "saveImg: 判断路径:ok");
try {
File file=new File(storedPath,fileName);
if(file.exists()){
Log.i(TAG, "saveImg: 判断文件:1");
file.delete();
}
Log.i(TAG, "saveImg: 判断文件:2");
file.createNewFile();
Log.i(TAG, "saveImg: 判断文件:ok");
FileOutputStream fos=new FileOutputStream(file);
fos.write(data);
fos.close();
return true;
} catch (IOException e) {
e.printStackTrace();
Log.i(TAG, "saveImg: 异常:"+e.getMessage());
return false;
}
} public Bitmap readImg(String fileName){
if(!isMounted()){
return null;
}
File imgFile=new File(storedPath,fileName);
if(imgFile.exists()){
return BitmapFactory.decodeFile(imgFile.getAbsolutePath());
}
return null;
} private boolean isMounted(){
String state=Environment.getExternalStorageState();
return state.equals(Environment.MEDIA_MOUNTED);
}

备注

在进行外部存储时,如果默认关闭了APP的存储空间权限,没有前往设置开启应用权限,即使manifest中正常注册权限,该APP仍让无法读写文件。调试日志如下:

-----------------------------------------------------------------------------------------------------------------------------------------------------------------

未开启App的存储权限
04-02 21:21:59.173 30863-30863/com.hex.demostorage I/DemoStorage: externalSave: 开始
04-02 21:21:59.407 30863-30863/com.hex.demostorage I/DemoStorage: externalSave: saveImg
04-02 21:21:59.408 30863-30863/com.hex.demostorage I/DemoStorage: saveImg: 开始
04-02 21:21:59.412 30863-30863/com.hex.demostorage I/DemoStorage: saveImg: 路径:/storage/emulated/0/hex/images
04-02 21:21:59.412 30863-30863/com.hex.demostorage I/DemoStorage: saveImg: 判断路径:ok
04-02 21:21:59.412 30863-30863/com.hex.demostorage I/DemoStorage: saveImg: 判断文件:2
04-02 21:21:59.414 30863-30863/com.hex.demostorage I/DemoStorage: saveImg: 异常:No such file or directory
04-02 21:21:59.414 30863-30863/com.hex.demostorage I/DemoStorage: externalSave: saveImg:false
04-02 21:21:59.414 30863-30863/com.hex.demostorage I/DemoStorage: externalSave: 结束
开启App的存储权限
04-02 21:22:48.519 31306-31306/com.hex.demostorage I/DemoStorage: externalSave: 开始
04-02 21:22:48.754 31306-31306/com.hex.demostorage I/DemoStorage: externalSave: saveImg
04-02 21:22:48.755 31306-31306/com.hex.demostorage I/DemoStorage: saveImg: 开始
04-02 21:22:48.759 31306-31306/com.hex.demostorage I/DemoStorage: saveImg: 路径:/storage/emulated/0/hex/images
04-02 21:22:48.760 31306-31306/com.hex.demostorage I/DemoStorage: saveImg: 判断路径:ok
04-02 21:22:48.760 31306-31306/com.hex.demostorage I/DemoStorage: saveImg: 判断文件:2
04-02 21:22:48.761 31306-31306/com.hex.demostorage I/DemoStorage: saveImg: 判断文件:ok
04-02 21:22:48.763 31306-31306/com.hex.demostorage I/DemoStorage: externalSave: saveImg:true
04-02 21:22:48.787 31306-31306/com.hex.demostorage I/DemoStorage: externalSave: 结束

-----------------------------------------------------------------------------------------------------------------------------------------------------------------

记录学习,记录成长!

一起学Android之Storage的更多相关文章

  1. Android开发学习之路-该怎么学Android(Service和Activity通信为例)

    在大部分地方,比如书本或者学校和培训机构,教学Android的方式都基本类似,就是告诉先上原理方法,然后对着代码讲一下. 但是,这往往不是一个很好的方法,为什么? ① 学生要掌握这个方法的用途,只能通 ...

  2. 菜鸟学Android编程——简单计算器《一》

    菜鸟瞎搞,高手莫进 本人菜鸟一枚,最近在学Android编程,网上看了一些视频教程,于是想着平时手机上的计算器应该很简单,自己何不尝试着做一个呢? 于是就冒冒失失的开撸了. 简单计算器嘛,功能当然很少 ...

  3. 学Android开发,入门语言java知识点

    学Android开发,入门语言java知识点 Android是一种以Linux为基础的开源码操作系统,主要使用于便携设备,而linux是用c语言和少量汇编语言写成的,如果你想研究Android,就去学 ...

  4. DoNet屌丝学Android(一)——Android开发准备工作 & No HelloWord & (真机)调试

    先乱扯淡一下吧,本人一.net屌丝,手持Android 4.2.2手机,Win7 x64本本,闲来无聊学习一下Android的开发,至于要开发啥玩意目前没有什么想法,就是想学学,搞不好是三分热度也有可 ...

  5. 从头学Android系列

    从头学Android系列 http://blog.csdn.net/worker90/article/category/888358

  6. 学Android开发 这19个开发工具助你顺风顺水

    学Android开发 这19个开发工具助你顺风顺水 要想快速开发一个Android应用,通常会用到很多工具,巧妙利用这些工具,能让我们的开发工作事半功倍,节省大量时间,下面大连Android开发培训小 ...

  7. 一步一步学android控件(之十五) —— DegitalClock & AnalogClock

    原本计划DigitalClock和AnalogClock单独各一篇来写,但是想想,两个控件的作用都一样,就和在一起写一篇了. DegitalClock和AnalogClock控件主要用于显示当前时间信 ...

  8. 一步一步学android控件(之十六)—— CheckBox

    根据使用场景不同,有时候使用系统默认的CheckBox样式就可以了,但是有时候就需要自定义CheckBox的样式.今天主要学习如何自定义CheckBox样式.在CheckBox状态改变时有时需要做一些 ...

  9. 【视频】零基础学Android开发:蓝牙聊天室APP(四)

    零基础学Android开发:蓝牙聊天室APP第四讲 4.1 ListView控件的使用 4.2 BaseAdapter具体解释 4.3 ListView分布与滚动事件 4.4 ListView事件监听 ...

随机推荐

  1. C语言 > 字符串和字符串函数

    输入 gets() 函数 : 1.gets() 从标准输入设备读取字符串,以回车结束读取,使用'\0'结尾,回车符'\n'被舍弃没有遗留在缓冲区. 2.可以用来输入带空格的字符串. 3.可以无限读取, ...

  2. bugku misc writeup(一个普通的压缩包)

    这个题做了好几个小时,因为没有writeup,一点一点摸索,做题思路写出来给大家交流 首先这是一个zip.rar压缩包,下载下来第一步就是拖进hexeditor中观察,检查下文件的头尾结构是否有问题, ...

  3. PAT1099:Build A Binary Search Tree

    1099. Build A Binary Search Tree (30) 时间限制 100 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN ...

  4. 分布式架构真正适用于大型互联网项目的架构! dubbo+zookeeper+springmvc+mybatis+shiro+redis

     分类: 分布式技术(3)    目录(?)[+]   平台简介 Jeesz是一个分布式的框架,提供项目模块化.服务化.热插拔的思想,高度封装安全性的Java EE快速开发平台. Jeesz本身集成D ...

  5. SSM-Spring-03:Spring中AOP的初窥和入门小案例

    ------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- AOP:面向切面编程 AOP的主要作用:是为了程序员更好的关注"业务",专心"做 ...

  6. 常见性能优化策略的总结 good

    阅读目录 代码 数据库 缓存 异步 NoSQL JVM调优 多线程与分布式 度量系统(监控.报警.服务依赖管理) 案例一:商家与控制区关系的刷新job 案例二:POI缓存设计与实现 案例三:业务运营后 ...

  7. 一个js小游戏----总结

    花了大概一天左右的功夫实现了一个js小游戏的基本功能,类似于“雷电”那样的小游戏,实现了随即怪物发生器,碰撞检测,运动等等都实现了,下一个功能是子弹轨迹,还有其他一些扩展功能,没有用库,也没有用web ...

  8. Javascript 中的map/reduce

    先填个坑,后面慢慢填 附上一篇不错的文章:https://segmentfault.com/a/1190000008719824

  9. NOI前的考试日志

    4.14 网络流专项测试 先看T1,不会,看T2,仙人掌???wtf??弃疗.看T3,貌似最可做了,然后开始刚,刚了30min无果,打了50分暴力,然后接着去看T1,把序列差分了一下,推了会式子,发现 ...

  10. BZOJ_1503_[NOI2004]郁闷的出纳员_权值线段树

    BZOJ_1503_[NOI2004]郁闷的出纳员_权值线段树 Description OIER公司是一家大型专业化软件公司,有着数以万计的员工.作为一名出纳员,我的任务之一便是统计每位员工的 工资. ...