前言

之前一直在讲AndroidUI的内容,但是还没有完结,之后会慢慢补充。今天讲讲其他的,关于数据持久化的内容。对于一个应用程序而言,不可避免的要能够对数据进行存储,Android程序也不例外。而在Android中,提供了几种实现数据持久化的方法。后面会分别介绍。

在Android中,可以使用几种方式实现数据持久化:

Shared Preferences:共享参数形式,一种以Key-Value的键值对形式保存数据的方式,Android内置的,一般应用的配置信息,推荐使用此种方式保存。

Internal Storage:使用Android设备自带的内存存储数据。

External Storage:使用外部存储设备存储数据,一般是指Sdcard。

SQLite Databases:以SQLite数据库存储结构化的数据。

Network Connection:使用基于网络的服务获取数据,可以参见另外一篇博客:Android--Apache HttpClient。

后面几天会分别介绍以上几种方式实现的数据持久化,对于SharedPreferences而言,之前写过一篇博客,但是自己不是很满意,之后有时间会再重新写一份关于SharedPreferences的博客,有兴趣的朋友可以先去看看,Android--使用SharedPreferences。今天先介绍Internal Storage以及External Storage。

Internal Storage

内部存储,在Android中,开发者可以直接使用设备的内部存储器中保存文件,默认情况下,以这种方式保存的和数据是只能被当前程序访问,在其他程序中是无法访问到的,而当用户卸载该程序的时候,这些文件也会随之被删除。

使用内部存储保存数据的方式,基本上也是先获得一个文件的输出流,然后以write()的方式把待写入的信息写入到这个输出流中,最后关闭流即可,这些都是Java中IO流的操作。具体步骤如下:

使用Context.openFileOutput()方法获取到一个FileOutputStream对象。

把待写入的内容通过write()方法写入到FileOutputStream对象中。

最后使用close()关闭流。

上面介绍的Context.openFileOutput()方法有两个重载函数,它们的签名分别是:

FileOutputStream openFileOutput(String name):以MODE_PRIVATE的模式打开name文件。

FileOutputStream openFileOutput(String name,int mode):以mode的模式打开name文件。

上面第二个重载函数中,mode为一个int类型的数据,这个一般使用Context对象中设置好的常量参数,有如下几个:

MODE_APPEND:以追加的方式打开一个文件,使用此模式写入的内容均追加在原本内容的后面。

MODE_PRIVATE:私有模式(默认),如果文件已经存在会重新创建并替换原文件,如果不存在直接创建。

MODE_WORLD_READABLE:以只读的方式打开文件。

MODE_WORLD_WRITEABLE:以只写的方式打开文件。

还有几个方法需要特别注意一下,这几个方法对于文件关系提供了更好的支持,配合上面介绍的方式,就可以对文件的数据进行常规的CRUD操作(增删改查),方法如下:

File getFIlesDir():获取文件系统的绝对路径。

boolean deleteFile(String name):删除一个指定文件名为name的文件。

String[] fileList():当前应用内部存储路径下的所有文件名。

讲了这么多,下面通过一个简单的Demo来演示一下上面提到的内容。在这个Demo中,指定文件名和内容,既可创建文件,并且可以对其内容进行追加、修改、删除、查询等操作。

android:layout_width="match_parent"android:layout_height="wrap_content"android:text="file name:" />

android:id="@+id/etInternalFilename"android:layout_width="match_parent"android:layout_height="wrap_content" />

android:layout_width="match_parent"android:layout_height="wrap_content"android:text="Content:" />

android:id="@+id/etInternalContent"android:layout_width="match_parent"android:layout_height="wrap_content" />

android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal" >

android:id="@+id/btnInternalSave"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="save" />

android:id="@+id/btnInternalDelete"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="delete" />

android:id="@+id/btnInternalAppend"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="append" />

android:id="@+id/btnInternalQuery"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="query" />

android:id="@+id/lvInternalData"android:layout_width="match_parent"android:layout_height="fill_parent" >

View Code

内部存储的操作类,对其实现CRUD操作:

packagecom.example.internal;importjava.io.ByteArrayOutputStream;importjava.io.File;importjava.io.FileInputStream;importjava.io.FileNotFoundException;importjava.io.FileOutputStream;importjava.io.IOException;importandroid.content.Context;importandroid.os.Environment;importandroid.util.Log;public classMyInternalStorage {//需要保存当前调用对象的Context

privateContext context;publicMyInternalStorage(Context context) {this.context =context;

}/*** 保存内容到内部存储器中

*@paramfilename 文件名

*@paramcontent 内容*/

public void save(String filename, String content) throwsIOException {//FileOutputStream fos=context.openFileOutput(filename,//Context.MODE_PRIVATE);

File file = newFile(context.getFilesDir(), filename);

FileOutputStream fos= newFileOutputStream(file);

fos.write(content.getBytes());

fos.close();

}/*** 通过文件名获取内容

*@paramfilename 文件名

*@return文件内容*/

public String get(String filename) throwsIOException {

FileInputStream fis=context.openFileInput(filename);

ByteArrayOutputStream baos= newByteArrayOutputStream();byte[] data = new byte[1024];int len = -1;while ((len = fis.read(data)) != -1) {

baos.write(data,0, len);

}return newString(baos.toByteArray());

}/*** 以追加的方式在文件的末尾添加内容

*@paramfilename 文件名

*@paramcontent 追加的内容*/

public void append(String filename, String content) throwsIOException {

FileOutputStream fos=context.openFileOutput(filename,

Context.MODE_APPEND);

fos.write(content.getBytes());

fos.close();

}/*** 删除文件

*@paramfilename 文件名

*@return是否成功*/

public booleandelete(String filename) {returncontext.deleteFile(filename);

}/*** 获取内部存储路径下的所有文件名

*@return文件名数组*/

publicString[] queryAllFile() {returncontext.fileList();

}

}

View Code

Activity代码:

packagecom.internalstorageactivity;importjava.io.IOException;importandroid.app.Activity;importandroid.os.Bundle;importandroid.view.View;importandroid.view.View.OnClickListener;importandroid.widget.AdapterView;importandroid.widget.AdapterView.OnItemClickListener;importandroid.widget.ArrayAdapter;importandroid.widget.Button;importandroid.widget.EditText;importandroid.widget.ListView;importandroid.widget.Toast;public class InternalStorageActivity extendsActivity {privateEditText etFilename, etContent;privateButton btnSave, btnQuery, btnDelete, btnAppend;privateListView lvData;

@Overrideprotected voidonCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);

setContentView(R.layout.main);

lvData=(ListView) findViewById(R.id.lvInternalData);

lvData.setOnItemClickListener(newOnItemClickListener(){

@Overridepublic void onItemClick(AdapterView> parent, View view, intposition,longid) {

System.out.println("1");

ListView lv=(ListView) parent;

ArrayAdapter adapter = (ArrayAdapter) lv

.getAdapter();

String filename=adapter.getItem(position);

etFilename.setText(filename);

MyInternalStorage myInternal= newMyInternalStorage(

InternalStorageActivity.this);try{

String content=myInternal.get(filename);

etContent.setText(content);

}catch(IOException e) {//TODO Auto-generated catch block

e.printStackTrace();

}

}

});

etFilename=(EditText) findViewById(R.id.etInternalFilename);

etContent=(EditText) findViewById(R.id.etInternalContent);

btnSave=(Button) findViewById(R.id.btnInternalSave);

btnSave.setOnClickListener(newOnClickListener() {

String filename= null;

String content= null;public voidonClick(View v) {

filename=etFilename.getText().toString();

content=etContent.getText().toString();

MyInternalStorage myInternal= newMyInternalStorage(

InternalStorageActivity.this);try{

myInternal.save(filename, content);

Toast.makeText(InternalStorageActivity.this, "保存文件成功",

Toast.LENGTH_SHORT).show();

}catch(IOException e) {//TODO Auto-generated catch block

e.printStackTrace();

Toast.makeText(InternalStorageActivity.this, "保存文件失败",

Toast.LENGTH_SHORT).show();

}

}

});

btnAppend=(Button) findViewById(R.id.btnInternalAppend);

btnAppend.setOnClickListener(newOnClickListener() {

String filename= null;

String content= null;public voidonClick(View v) {

filename=etFilename.getText().toString();

content=etContent.getText().toString();

MyInternalStorage myInternal= newMyInternalStorage(

InternalStorageActivity.this);try{

myInternal.append(filename, content);

Toast.makeText(InternalStorageActivity.this, "保存内容追加成功",

Toast.LENGTH_SHORT).show();

}catch(IOException e) {//TODO Auto-generated catch block

e.printStackTrace();

Toast.makeText(InternalStorageActivity.this, "文件内容追加失败",

Toast.LENGTH_SHORT).show();

}

}

});

btnQuery=(Button) findViewById(R.id.btnInternalQuery);

btnQuery.setOnClickListener(newOnClickListener() {public voidonClick(View v) {

MyInternalStorage myInternal= newMyInternalStorage(

InternalStorageActivity.this);

String[] files=myInternal.queryAllFile();

ArrayAdapter fileArray = new ArrayAdapter(

InternalStorageActivity.this,

android.R.layout.simple_list_item_1, files);

lvData.setAdapter(fileArray);

Toast.makeText(InternalStorageActivity.this, "查询文件列表",

Toast.LENGTH_SHORT).show();

}

});

btnDelete=(Button) findViewById(R.id.btnInternalDelete);

btnDelete.setOnClickListener(newOnClickListener() {public voidonClick(View v) {

String filename=etFilename.getText().toString();

;

MyInternalStorage myInternal= newMyInternalStorage(

InternalStorageActivity.this);

myInternal.delete(filename);

Toast.makeText(InternalStorageActivity.this, "删除文件成功",

Toast.LENGTH_SHORT).show();

}

});

}

}

View Code

使用内部存储的方式进行数据持久化,文件的地址将保存在/data/data//files/路径下,上面创建了三个文件,最后删掉了一个,如果是使用的模拟器,可以直接在File Explorer中查看:

缓存(cache)

既然提到了内部存储,这里再简单的说说关于缓存文件(cache files)。cache files的操作与操作内部存储中的文件方式基本一致,只是获取文件的路径有说不同。如果需要使用缓存的方式进行数据持久话,那么需要使用Context.getCacheDir()方法获取文件保存的路径。

对于缓存文件而言,当设备内部内存存储空间不足的时候,Android会有自动删除的机制删除这些缓存文件,用来恢复可用空间,所以对于缓存文件而言,内容一般最好控制在1MB之下,并且也不要存放重要的数据,因为很可能下次去取数据的时候,已经被Android系统自动清理了。

External Storage

使用外部存储实现数据持久化,这里的外部存储一般就是指的是sdcard。使用sdcard存储的数据,不限制只有本应用访问,任何可以有访问Sdcard权限的应用均可以访问,而Sdcard相对于设备的内部存储空间而言,会大很多,所以一般比较大的数据,均会存放在外部存储中。

使用SdCard存储数据的方式与内部存储的方式基本一致,但是有三点需要注意的:

第一点,需要首先判断是否存在可用的Sdcard,这个可以使用一个访问设备环境变量的类Environment进行判断,这个类提供了一系列的静态方法,用于获取当前设备的状态,在这里获取是否存在有效的Sdcard,使用的是Environment.getExternalStorageState()方法,返回的是一个字符串数据,Environment封装好了一些final对象进行匹配,除了Environment.MEDIA_MOUNTED外,其他均为有问题,所以只需要判断是否是Environment.MEDIA_MOUNTED状态即可。

第二点,既然转向了Sdcard,那么存储的文件路径就需要相对变更,这里可以使用Envir.getExternalStorageDirectory()方法获取当Sdcard的根目录,可以通过它访问到相应的文件。

第三点,需要赋予应用程序访问Sdcard的权限,Android的权限控制尤为重点,在Android程序中,如果需要做一些越界的操作,均需要对其进行授权才可以访问。在AndroidManifest.xml中添加代码:

因为访问Sdcard的方式和访问内部存储的方式差不多,这里就展示一个Save的方法,用于保存文件,其他CRUD操作,这里就不再一一给出了。

public void saveToSdcard(String filename, String content) throwsIOException {if(Environment.MEDIA_MOUNTED.equals(Environment

.getExternalStorageState())) {

Log.i("main", "本设备有存储卡!");

File file= newFile(Environment.getExternalStorageDirectory(),

filename);

FileOutputStream fos= null;

fos= newFileOutputStream(file);

fos.write(content.getBytes());

fos.close();

}

}

View Code

而如果使用SdCard存储文件的话,存放的路径在Sdcard的根目录下,如果使用模拟器运行程序的话,创建的文件在/mnt/sdcard/目录下:

补充:对于现在市面上很多Android设备,自带了一个大的存储空间,一般是8GB或16GB,并且又支持了Sdcard扩展,对于这样的设备,使用Enviroment.getExternalStorageDirectory()方法只能获取到设备自带的存储空间,对于另外扩展的Sdcard而言,需要修改路径。

android平台上持久化存储3种手段_Android--数据持久化之内部存储、Sdcard存储相关推荐

  1. android平台上持久化存储3种手段_Android 数据持久化==存储数据的五种方法

    1.使用SharedPreferences存储数据 2.文件存储数据 3.SQLite数据库存储数据 4.使用ContentProvider存储数据 5.网络存储数据 第一种: 使用SharedPre ...

  2. MVP在Android平台上的应用

    2019独角兽企业重金招聘Python工程师标准>>> MVP在Android平台上的应用 原文链接 : Introduction to Model-View-Presenter o ...

  3. 在 Android* 平台上设置原生 OpenGL ES*

    Setting up Native OpenGL ES* on Android* Platforms final.docx BSD2.0.txt ParticleSystemNDK.zip READM ...

  4. Android平台上最好的几款免费代码编辑器

    概述:使用正确的开发工具能够快速有效地完成源代码的编写和测试,使编程事半功倍.这里介绍了在Android平台上5款最好的代码编辑器,帮助你作出选择. 使用正确的开发工具能够快速有效地完成源代码的编写和 ...

  5. Android平台上最好的几款免费的代码编辑器(转载)

    概述:使用正确的开发工具能够快速有效地完成源代码的编写和测试,使编程事半功倍.这里介绍了在Android平台上5款最好的代码编辑器,帮助你作出选择. 使用正确的开发工具能够快速有效地完成源代码的编写和 ...

  6. 响应式编程之二:RxJava概述:在Android平台上开发详解

    RxJava 到底是什么 RxJava 好在哪 API 介绍和原理简析 1. 概念:扩展的观察者模式 观察者模式 RxJava 的观察者模式 2. 基本实现 1) 创建 Observer 2) 创建 ...

  7. cocos2d js调用java_【cocos2d-js官方文档】二十四、如何在android平台上使用js直接调用Java方法...

    在cocos2d-js 3.0beta中加入了一个新特性,在android平台上我们可以通过反射直接在js中调用java的静态方法.它的使用方法很简单: var o = jsb.reflection. ...

  8. (转) Android平台上关于IM的实践总结

    前言 IM通信在互联网发展到现在已经是码农的世界里人尽皆知的技术,特别在当下移动互联网迅猛发展的时代这种技术的开发也更加火热,其中老牌的代表作就有QQ和MSN,和最近新崛起的微信,默默,易信,来往等眼 ...

  9. android 身份认证技术,Android平台上基于人脸识别的身份认证系统的设计与实现

    摘要: 随着移动互联网与人工智能技术的发展,基于个人特征的生物识别技术代替传统的身份验证方式已经是大势所趋.而人脸识别是生物识别技术的一个重要组成部分,拥有其他生物识别技术没有的独特优势.本文主要针对 ...

最新文章

  1. 信息科学部鼓励科学家更多瞄准“原创”研究
  2. Ecsotre 参考
  3. 打印两个有序链表的公共部分
  4. 劳心者、劳力者或CEO、CTO各得其所,足矣
  5. The method getTextContent() is undefined for the type Node 错误解决办法
  6. 校园网未能找到pppoe服务器6,校园网PPPOE接入认证系统的研究与实现.doc
  7. OCM考试经历:注意事项
  8. 通过开放重定向接管 GitHub Gist 账户,获奖$1万(GitHub $6.1万奖金系列之三)
  9. 无法安装 Microsoft Visual Studio 2010 Service Pack 1
  10. jenkins邮件配置(系统邮件和插件)
  11. 阶段5 3.微服务项目【学成在线】_day01 搭建环境 CMS服务端开发_20-页面查询服务端开发-创建CMS服务工程-测试Controller...
  12. tomcat6url请求400错误(%2F与%5C)
  13. 浏览器UserAgent的趣味史
  14. 5G即将全面普及,我们到底该换手机卡还是换手机?
  15. 2022年4月加拿大MogaFX外汇和衍生品市场活动三年期央行调查
  16. 脑科学家:神经科学与大数据的结合带来的新领域
  17. 蓝鹰立德丨2021年个税汇算清缴之未雨绸缪(上)
  18. Java网课资源分享
  19. 如何使用uni-app做一个音乐播放器
  20. 光模块第五节之COB工艺

热门文章

  1. Java程序为身份证照片添加马赛克
  2. css label 居中布局_label标签 html教程
  3. 为什么狗狗听到铃声会叫
  4. Python常见数据处理技术——数据的概览与清洗、多表合并与连接、数据的汇总
  5. 一行行的代码解密马尔可夫链
  6. 使用小波包变换分析信号的matlab程序,使用小波包变换分析信号的MATLAB程序(转)...
  7. 高德API支持WMS服务器,GCJ02-Correct
  8. Trx-address和交易的address
  9. CreateJs-EaselJs基础
  10. Halcon 之 Measure_Pairs