概述

在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. SpringMVC中的异常处理

    springmvc在处理请求过程中出现异常信息交由异常处理器进行处理,自定义异常处理器可以实现一个系统的异常处理逻辑. 1. 异常处理思路 系统中异常包括两类:预期异常和运行时异常RuntimeExc ...

  2. 十八、Hadoop学记笔记————Hbase架构

    Hbase结构图: Client,Zookeeper,Hmaster和HRegionServer相互交互协调,各个组件作用如下: 这几个组件在实际使用过程中操作如下所示: Region定位,先读取zo ...

  3. SSM-SpringMVC-16:SpringMVC中小论注解式开发之访问方式篇

     ------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 访问方式可以指定,打个比方,你通过get方式进入登陆页面,通过post发送ajax数据库校验或者post提交 ...

  4. Linux kernel的中断子系统之(一):综述

    返回目录:<ARM-Linux中断系统>. 总结: 一从作为一名驱动工程师角度看,用好中断需要正确认识request_threaded_irq/request_irq关系.中断临界区保护. ...

  5. binlog——逻辑复制的基础

    Ⅰ.binlog定义和作用 1.1 定义 记录每次数据库的逻辑操作(包括表结构变更和表数据修改) 包含:binlog文件和index文件 1.2 作用 复制:从库读取主库binlog,本地回放实现复制 ...

  6. Base64 image

    [前端攻略]:玩转图片Base64编码 什么是 base64 编码? 我不是来讲概念的,直接切入正题,图片的 base64 编码就是可以将一副图片数据编码成一串字符串,使用该字符串代替图像地址. 这样 ...

  7. border-radius 详解及示例

    border-radius [ˈbɔrdə(r)] - [ˈrediəs]   英文示意: border:边界,国界,边疆 radius:半径,范围   定义: 复合写法: border-radius ...

  8. 五个最佳RSS新闻阅读器

    文章出自http://www.williamlong.info/archives/1591.html 在博客和在线新闻充斥的互联网上,大量信息已经使得用户阅读量过载,幸运的是,通过RSS Feed提供 ...

  9. Python Web 框架:Tornado

    1.Tornado Tornado:python编写的web服务器兼web应用框架 1.1.Tornado的优势 轻量级web框架 异步非阻塞IO处理方式 出色的抗负载能力 优异的处理性能,不依赖多进 ...

  10. GitHub 系列之「怎样使用 GitHub?」

    1.写在前边的话,为什么要写CitHub? 跟朋友在交流的时候听到求职的时候发现有些公司要附Github帐号,一个优秀的 GitHub 账号当然能让你增色不少.自己之前听说过,但没有花时间研究,最后花 ...