概述

在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. AngularJS 最常用的几种功能

    AngularJS 最常用的几种功能 2017-04-13 吐槽阿福 互联网吐槽大会 第一 迭代输出之ng-repeat标签ng-repeat让table ul ol等标签和js里的数组完美结合 1 ...

  2. Map Reduce和流处理

    欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由@从流域到海域翻译,发表于腾讯云+社区 map()和reduce()是在集群式设备上用来做大规模数据处理的方法,用户定义一个特定的映射 ...

  3. mybatis查询异常-Error querying database. Cause: java.lang.ClassCastException: org.apache.ibatis.executor.ExecutionPlaceholder cannot be cast to java.util.List

    背景,mybatis查询的时候直接取的sqlsession,没有包装成SqlSessionTemplate,没有走spring提供的代理. 然后我写的获取sqlsession的代码没有考虑到并发的情况 ...

  4. LR测试

    LoadRunner种预测系统行性能负载测试工具通模拟千万用户实施并发负载及实性能监测式确认查找问题LoadRunner能够整企业架构进行测试通使用 LoadRunner企业能限度缩短测试间优化性能加 ...

  5. Qtp自动测试工具

    QTP是基于GUI界面的自动化测试工具,用于系统的功能测试. QTP录制的是鼠标和键盘的消息.QTP录制回放时基于windows操作系统的消息机制.QTP在录制时监听应用程序的消息,监听到之后把消息放 ...

  6. 解决window.showModalDialog在Firefox无法支持

    在网页程序中,有时我们会希望使用者按下按钮后开启一个保持在原窗口前方的子窗口,而在IE中,我们可以使用showModalDialog来达成,语法如下 : vReturnValue = window.s ...

  7. sqlserver 日期与字符串之间的转换

    字符转换为日期时,Style的使用 --1. Style=101时,表示日期字符串为:mm/dd/yyyy格式SELECT CONVERT(datetime,'11/1/2003',101)--结果: ...

  8. app后端设计(6)-- LBS

    在LBS的应用中,一个基本的需求是查找附近的用户,现在有两种做法: 1. 使用mysql的空间数据库,具体做法参考:http://blog.sina.com.cn/s/blog_a48af8c0010 ...

  9. RabbitMQ (五)主题(Topic)

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/37706355 上一篇博客中,我们进步改良了我们的日志系统.我们使用direct类 ...

  10. 译MassTransit 生产消息

    生产消息 应用程序或服务可以使用两种不同的方法生产消息.可以使用Sead发送消息,也可以使用Publish发布消息.每个方法的行为是非常不同的,但是通过查看每个特定方法所涉及的消息类型,可以很容易理解 ...