Android数据持久化存储

Android数据持久化存储共有四种方式,分别是文件存储、SharedPreferences、Sqlite数据库和ContentProvider。在本篇幅中只介绍前面三种存储方式,因为ContentProvider属于android四大组件之一,所以它的数据存储方式在介绍四大组件的时候说明。

1、文件存储

文件存储不对存储的内容进行任何的格式化处理,所有数据都是原封不动地保存到文件当中的,因而它比较适合用于存储一些简单的文本数据或二进制数据。

文件存储有两种方式,一是存储到手机内存中(memory),一是存储到sd卡中。

1.1、存储到手机内存中

1)将数据存储到文件中

Context类中提供了一个 openFileOutput()方法,可以用于将数据存储到指定的文件中。

方法介绍:


openFileOutput(name, mode):

name:是文件名,注意这里指定的文件名不可以包含路径,因为所有的文件都是默认存储到/data/data/<package name>/files/(等价于 getFilesDir())目 录下 的

mode:是文件的操作模式 ,

MODE_PRIVATE:默认的操作模式,同名文件内容会被覆盖。

MODE_APPEND则表示 如果该文件已存在就往文件里面追加内容,不存在就创建新文件。

还有另外两种(android 4.2被废弃),MODE_WORLD_READABLE和MODE_WORLD_WRITEABLE,这两种模式表示允许其他的应用程序对我们程序中的文件进行读写操作。

openFileOutput()方法返回的是一个 FileOutputStream对象,得到了这个对象之后就可以 使用 Java流的方式将数据写入到文件中了。


public void save() {

String data = "Data to save";

FileOutputStream out = null;

BufferedWriter writer = null;

try {

out = openFileOutput("data", Context.MODE_PRIVATE);

writer = new BufferedWriter(new OutputStreamWriter(out));

writer.write(data);

} catch (IOException e) {

e.printStackTrace();

} finally {

try {

if (writer != null) {

writer.close();

}

} catch (IOException e) {}

}

}

}

以上代码就是将将一 段文本内容保存到文件中。

完成将数据存储到文件中,接下来如何从文件中读取数据呢?

2)从文件中读取数据

Context类中还提供了一个 openFileInput()方法,用于从文件中读取数据。

这个方法只接收一个参数,即要读取的文件名,使用openFileInput("filename")读取存放在/data/data/<package name>/files目录应用私有的文件。该方法返回一个 FileInputStream对象,得到了这个对象之后再通过 Java流的方式就可以将数据读取出来了。


public String load() {

FileInputStream in = null;

BufferedReader reader = null;

StringBuilder content = new StringBuilder();

try {

in = openFileInput("data");

reader = new BufferedReader(new InputStreamReader(in));

String line = "";

while ((line = reader.readLine()) != null) {

content.append(line);

}

} catch (IOException e) {

e.printStackTrace();

} finally {

if (reader != null) {

try {

reader.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

return content.toString();

}

1.2、存储到sd卡中

前面说了file储存,数据是存储在应用程序内的,文件大小受到限制;当要存储大的文件时,就要使用sd卡方式存储了。使用sd卡存储主要是使用Environment这个类的功能。

1)将数据存储到sd卡中

Environment类介绍:

①常用常量:

String MEDIA_MOUNTED:外部存储器可读可写

MEDIA_MOUNTED_READ_ONLY:外部存储器只读

②常用方法:

getExternalStorageDirectory ():获取SDCard的目录,/mnt/sdcard

getExternalStorageState ():获取外部存储器的当前状态

通过简单价绍Environment类的使用,接下来就是sd卡读写数据了。以下是往sd卡读写数据的步骤:

1)判断sd卡的状态

2)获取存储器的目录,即sd卡的目录

3)使用IO流对sd卡进行文件的读写操作

4)在清单文件中添加权限

写入数据到sd卡中代码如下:


public void write2Sd(){

if (Environment.getExternalStorageState().equals(

Environment.MEDIA_MOUNTED)) {

String content = edtContent.getText().toString();

try {

// 获取SDcard路径

File sdCardDir = Environment

.getExternalStorageDirectory();

// SDCard目录:/mnt/sdcard

String sdcardPath = sdCardDir.getAbsolutePath();

File file = new File(sdCardDir, FILE_NAME);

// File file = new File(sdcardPath

// + File.separator + FILE_NAME);

// 以指定文件创建RandomAccessFile对象

RandomAccessFile raf = new RandomAccessFile(file, "rw");

// 将文件记录指针移动最后

raf.seek(file.length());

// 输出文件内容

raf.write(content.getBytes());

raf.close();

} catch (Exception e) {

// TODO: handle exception

}

}

}

以上代码可知,往sd卡中写数据先调用getExternalStorageState()判断sd卡状态,接着获取sd卡的存储路径,以路径很文件名创建文件,最后使用RandomAccessFile 类存储数据,使用该类的好处是可以定位的指定位置进行读写数据。

2)从sd卡中读取数据


public void readFromSd(){

if (Environment.getExternalStorageState().equals(

Environment.MEDIA_MOUNTED)) {

// 获取SDcard路径

StringBuilder sb = new StringBuilder();

try {

File sdCardDir = Environment

.getExternalStorageDirectory();

File file = new File(sdCardDir, FILE_NAME);

InputStream inputStream = new FileInputStream(file);

int len = 0;

byte[] buffer = new byte[1024];

while ((len = inputStream.read(buffer)) != -1) {

sb.append(new String(buffer, 0, len));

}

tvResult.setText(sb.toString());

// 关闭流

inputStream.close();

} catch (Exception e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

2、SharedPreferences存储

2.1、将数据存储到 sp中

SharedPreferences类,它是一个轻量级的存储类,适合用于保存软件配置参数。SharedPreferences是使用键值对的方式来存储数据的,存储数据是以xml文件形式存储,文件存放在/data/data/<package name>/shared_prefs目录下。

步骤:

1)获取SharedPreferences对象。

要想使用sp来存储数据,首先需要获取到sp对象。Android 中主要提供了三种方法用于得到 sp对象。

1、Context类中的 getSharedPreferences(name, mode)方法

Name:用于指定 SharedPreferences文件的名称

mode指定操作模式,和文件存储模式一样。

2、Activity类中的 getPreferences(mode)方法

使用这个方法时会自动将当前活动的类名作为 SharedPreferences的文件名。

3. PreferenceManager类中的 getDefaultSharedPreferences(context)方法 
这是一个静态方法,使用当前应用程序的包名作为前缀名来命名文件。

2)调用sp对象的edit()方法来获取一个SharedPreferences.Editor对象。

3)向 SharedPreferences.Editor 对象中添加数据。比如添加一个布尔型数据就使用 putBoolean方法,添加一个字符串则使用 putString()方法,以此类推。

4)调用 commit()方法将添加的数据提交,从而完成数据存储操作

2.2、从sp中读取数据

步骤:

1)获取SharedPreferences对象。

2)然后分别调用它的 geXxx()方法获取存储的值。如getString()、getInt()和 getBoolean(),没有找到相应的值就会使用方法中传入的默认值来代替

3、Sqlite数据库存储

SQLite是一款轻量级的关系型数据库,它的运算速度非常快, 占用资源很少,通常只需要几百 K的内存就足够了。SQLite 不仅支持标准的SQL语法,还遵循了数据库的 ACID事务。

Android提供了一个 SQLiteOpenHelper帮助类,借助这个类就可以非常简单地对数据库进行创建和升级。

SQLiteOpenHelper是一个抽象类,有两个抽象方法,分别是 onCreate()和 onUpgrade(),分别在这两个方法中去实现创建、升级数据库的逻辑。 SQLiteOpenHelper中还有两个实例方法,getReadableDatabase() 和 getWritableDatabase()。这两个方法都可以创建或打开一个现有的数据库(如果数据库已存在 则直接打开,否则创建一个新的数据库),并返回一个可对数据库进行读写操作的对象。

3.1、创建数据库

因为SQLiteOpenHelper是一个抽象类,创建数据库的时候可以创建一个类继承SQLiteOpenHelper,并重写其两个抽象方法。新建MyDatabaseHelper 类继承自 SQLiteOpenHelper,代码如下所示:


public class MyDatabaseHelper extends SQLiteOpenHelper {

public static final String CREATE_BOOK = "create table book ("

+ "id integer primary key autoincrement, "

+ "author text, "

+ "price real, "

+ "pages integer, name text)";

private Context mContext;

public MyDatabaseHelper(Context context, String name,

CursorFactory factory, int version) {

super(context, name, factory, version);

mContext = context;

}

@Override

public void onCreate(SQLiteDatabase db) {

db.execSQL(CREATE_BOOK);

Toast.makeText(mContext, "Create succeeded", Toast.LENGTH_SHORT).show();

}

@Override

public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)    {

}

}

如上所示,先把建表语句写成字符串常量, 在onCreate()方法中调用  SQLiteDatabase的 execSQL()方法去执行这条建表语句,以保证数据库创建的同时也成功的创建Book表。

然后再布局文件加入了一个id是.create_database的Button按钮,用于创建数据库。最后修改 MainActivity中的代码,如下所示:


public class MainActivity extends Activity {

private MyDatabaseHelper dbHelper;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

dbHelper = new MyDatabaseHelper(this, "BookStore.db", null, 1);

Button createDatabase = (Button) findViewById(R.id.create_database);

createDatabase.setOnClickListener(new OnClickListener() {

@Override

public void onClick(View v) {

dbHelper.getWritableDatabase();

}

});

}

}

如上所示,在 onCreate()方法中构建了一个 MyDatabaseHelper对象,并且通过构造函数的参数将数据库名指定为 BookStore.db,版本号指定为 1,然后在 Create database按钮的点击事件里调用了getWritableDatabase()方法。这样当第一次点击按钮时,就会检测 到当前程序中并没有BookStore.db这个数据库,于是会创建该数据库并调用MyDatabaseHelper中的 onCreate()方法同时也创建Book表。

3.2、升级数据库

MyDatabaseHelper中的onUpgrade() 方法是用于对数据库进行升级的。

接着我们再添加一张 Category表用于记录书籍的分类,修改MyDatabaseHelper 代码如下:


public class MyDatabaseHelper extends SQLiteOpenHelper {

public static final String CREATE_CATEGORY = "create table Category ("

+ "id integer primary key autoincrement, "

+ "category_name text, "

+ "category_code integer)";

.....

@Override

public void onCreate(SQLiteDatabase db) {

db.execSQL(CREATE_BOOK);

db.execSQL(CREATE_CATEGORY);

}

@Override

public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

switch (oldVersion) {

case 1:

db.execSQL(CREATE_CATEGORY);

case 2:

db.execSQL("alter table Book add column category_id integer");

default:

}

}

}

可以看到,这里在onUpgrade()方法中加入了一个switch判断,如果oldVersion等于1,就再创建一个CATEGORY表。接着只需要在创建MyDatabaseHelper 时构造函数第四个参数改成大于1的整数即可。

紧接着,发现CATEGORY表少添加了category_id列,为了保留原有数据库的数据,只需在添加一个case语句,使用alter..add添加该列就行,注意case之间没有break。使用这种方式升级数据库就不会导致表中的数据丢失问题。

3.3、数据库的CRUD操作

数据库的crud其中 C 代表添加 (Create),R代表查询(Retrieve),U代表更新(Update) ,D代表删除(Delete)。每一种操 作又各自对应了一种 SQL命令。

调用SQLiteOpenHelper的getReadableDatabase()或getWritableDatabase()

方法是可以用于创建和升级数据库的,这两个方法还都会返回一个SQLiteDatabase 对象,借助这个对象就可以对数据进行 CRUD操作。

1)C 数据库的add操作

SQLiteDatabase中的 insert(table, nullColumnHack, values)方法

Table:表名

nullColumnHack:通常用不到,直接传null。

Value:ContentValue,是map集合,表示待添加的数据。


public void add() {

SQLiteDatabase db = dbHelper.getWritableDatabase();

ContentValues values = new ContentValues(); // 开始组装第一条数据

values.put("name", "The Da Vinci Code");

values.put("author", "Dan Brown");

values.put("pages", 454);

values.put("price", 16.96);

db.insert("Book", null, values);

}

2)R数据库的query操作

SQLiteDatabase中的query(table, columns, selection, selectionArgs, groupBy, having, orderBy)方法:

table, 表名

columns, 指定去查询哪几列

selection, selectionArgs, 指定约束条件和占位符,表示查询哪几行

groupBy, 对查询结果进行group by操作

having, 对groupBy后的数据进行进一步过滤

orderBy,对查询的结果进行排序


public void query() {

SQLiteDatabase db = dbHelper.getWritableDatabase();

// 查询Book表中所有的数据

Cursor cursor = db.query("Book", null, null, null, null, null, null);

if (cursor.moveToFirst()) {

do {

// 遍历Cursor对象

String name = cursor.getString(cursor.getColumnIndex("name"));

String author = cursor.getString(cursor

.getColumnIndex("author"));

int pages = cursor.getInt(cursor.getColumnIndex("pages"));

double price = cursor.getDouble(cursor.getColumnIndex("price"));

} while (cursor.moveToNext());

}

cursor.close();

}

3)U数据库的update操作

SQLiteDatabase中的 update(table, values, whereClause, whereArgs)方法

Table:表名

Value:ContentValue,是map集合。

whereClause、whereArgs:指定第三和第四个参数用于指定修改哪些行


public void update() {

SQLiteDatabase db = dbHelper.getWritableDatabase();

ContentValues values = new ContentValues();

values.put("price", 10.99);

db.update("Book", values, "name = ?",

new String[] { "xiao ming" });

}

4)D数据库的delete操作

SQLiteDatabase中的 delete(table, whereClause, whereArgs)

table,表名

whereClause, whereArgs:指定要删除哪些行,对应sql语句的where部分。


public void delete() {

SQLiteDatabase db = dbHelper.getWritableDatabase();

db.delete("Book", "pages > ?", new String[] { "500" });

}

3.4、使用SQL操作数据库

Android中支持使用原生的sql语句执行数据库的增删改查操作。具体如下:

添加数据的方法如下:

db.execSQL("insertintoBook(name,author,pages,price)values(?,?,?,?)", new String[] { "The Da Vinci Code", "Dan Brown", "454", "16.96" });

更新数据的方法如下:

db.execSQL("updateBooksetprice=? wherename=?",new String[]{"10.99", "The Da Vinci Code" });

删除数据的方法如下:

db.execSQL("delete from Book where pages > ?", new String[] { "500" });

查询数据的方法如下:

db.rawQuery("select * from Book", null);

3.5、使用LitePal框架完成Android数据库的存储

使用SQLiteOpenHelper有一个弊端,就是如果数据库中某一列已经没有用了,我想把这一列删除,使用SQLite是无法实现删除某一列的(开发中多是忽视它,反正以后也用不到,留着也占用不了多少空间),另外就是如果表之间存在关联关系,建表语句就会变得很复杂,因此使用LitePal来自动建立表关联又是一个非常不错的选择,我们不需要关心什么外键、中间表等实现的细节,只需要在对象中声明好它们相互之间的引用关系,LitePal就会自动在数据库表之间建立好相应的关联关系了。

注:虽然使用Litepal框架可以轻松实习表的关联,但表的关联知识了解下还是有必要的。多表设计数据库口诀:

一对一关联的实现方式是用外键,多对一关联的实现方式也是用外键(外键必须加载多方),多对多关联的实现方式是用中间表。

关于使用LitePal的教程可以参考这篇博客:

http://blog.csdn.net/guolin_blog/article/details/38461239

LitePal开源项目地址:https://github.com/LitePalFramework/LitePal

时间: 2024-10-26 12:51:43

Android数据持久化存储的相关文章

饿了么开源项目:便捷高效的Android数据持久化存储框架

版权所有.所有权利保留. 欢迎转载,转载时请注明出处: http://blog.csdn.net/xiaofei_it/article/details/51436972 Android应用开发时经常要对许多数据进行持久化存储,便于以后访问. 对于int.double.boolean这些基本数据,可以使用SharedPreference.对于一些对象,往SharedPreference里存储的时候需要使用序列化技术.如果对象很大,或者碰到列表.数组等结构,就必须使用数据库.而使用数据库比较麻烦,成

数据持久化存储

概论 所谓的持久化,就是将数据保存到硬盘中,使得在应用程序或机器重启后可以继续访问之前保存的数据.在iOS开发中,有很多数据持久化的方案,接下来我将尝试着介绍一下5种方案: plist文件(属性列表) preference(偏好设置) NSKeyedArchiver(归档) SQLite 3 CoreData 沙盒 在介绍各种存储方法之前,有必要说明以下沙盒机制.iOS程序默认情况下只能访问程序自己的目录,这个目录被称为“沙盒”. 1.结构 既然沙盒就是一个文件夹,那就看看里面有什么吧.沙盒的目

iOS数据持久化存储

本文中的代码托管在github上:https://github.com/WindyShade/DataSaveMethods 相对复杂的App仅靠内存的数据肯定无法满足,数据写磁盘作持久化存储是几乎每个客户端软件都需要做的.简单如"是否第一次打开"的BOOL值,大到游戏的进度和状态等数据,都需要进行本地持久化存储.这些数据的存储本质上就是写磁盘存文件,原始一点可以用iOS本身支持有NSFileManager这样的API,或者干脆C语言fwrite/fread,Cocoa Touch本身

Swift - 使用Core Data进行数据持久化存储

一,Core Data介绍 1,Core Data是iOS5之后才出现的一个数据持久化存储框架,它提供了对象-关系映射(ORM)的功能,即能够将对象转化成数据,也能够将保存在数据库中的数据还原成对象. 2,虽然其底层也是由类似于SQL的技术来实现,但我们不需要编写任何SQL语句,有点像Java开发中的Hibernate持久化框架 3,Core Data数据最终的存储类型可以是:SQLite数据库,XML,二进制,内存里,或自定义数据类型. 4,与SQLite区别:只能取出整个实体记录,然后分解,

iOS开发之数据持久化存储

概论 数据持久化存储:所谓持久化存储就是将数据保存到硬盘中,使得应用程序或者机器在重启后可以访问之前保存的数据. 常见方式: plist文件(属性列表) preference(偏好设置) NSKeyedArchiver(归档) SQLite3(数据库) CoreData(苹果基于数据库封装的持久化存储工具,这种方式效率不高,因为会帮我们动态生成很多重复的代码,我只有写XMPP的时候会用一下,因为XMPP里面的存储用的就是CoreData) 沙盒 说到持久化存储就不得不说一下苹果的沙盒机制,苹果的

redis的数据持久化存储

redis的数据持久化存储 Redis是一个支持持久化的内存数据库,也就是说redis需要经常将内存中的数据同步到硬盘来保证持久化.Redis支持两种持久化方式: 一.snapshotting(快照)方式快照是默认的持久化方式.这种方式是将内存中数据以快照的方式写入到二进制文件中,默认的文件名为dump.rdb.我们可以配置redis在n秒内如果超过若干个key被修改就自动做快照持久保存. 在约87行,有默认的快照策略(指定在多长时间内,有多少次更新操作,就将数据同步到数据快照文件,可以多个条件

[Xcode10 实际操作]七、文件与数据-(14)数据持久化存储框架CoreData的使用:删除CoreData中的数据

本文将演示如何删除数据持久化对象. 在项目导航区,打开视图控制器的代码文件[ViewController.swift] 1 import UIKit 2 //引入数据持久化存储框架[CoreData] 3 import CoreData 4 5 class ViewController: UIViewController { 6 7 override func viewDidLoad() { 8 super.viewDidLoad() 9 // Do any additional setup a

python 基础之数据持久化存储

###数据持久化存储 - 说明:持久化存储方案,普通文件.数据库.序列化 - 示例: ```python import pickle class Person: def __init__(self, name, age): self.name = name self.age = age def __str__(self): return 'name:{} age:{}'.format(self.name, self.age) xiaoming = Person('xiaoming', 20) #

Android开发之数据持久化存储二

一.目标 以QQ登陆为例,继续完成昨天没有完成的任务,实现数据的存储和回显读取,并且学会往SD卡内存储信息 二.源程序代码 package com.example.qq_logindemo; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import android.text.TextUtils; import android.util.Log; import android.view.Vie