数据持久化技术
一. SQLite数据库存储
简介:
SQLite,是一款轻量级的关系型数据库,是遵守ACID的关系型数据库管理系统,它的设计目标是嵌入式。由于它占用的资源非常少,所以在很多嵌入式设备都是用SQLite来存储数据。并且它目前支持Windows/Linux等等主流的操作系统,兼容性不错。Android作为目前主流的移动操作系统,完全符合SQLite占用资源少的优势,故在Android平台上,集成了一个嵌入式关系型数据库—SQLite。如果开发 Android 应用程序中,一定需要在 Android 上存储数据,使用SQLite 数据库是一种非常好的选择。
SQLite可以看作为一个API库、数据库引擎库
1.轻量级:使用 SQLite 只需要带一个动态库,就可以享受它的全部功能,而且那个动态库的尺寸相当小。
2.独立性:SQLite 数据库的核心引擎不需要依赖第三方软件,也不需要所谓的“安装”。
2.隔离性:SQLite 数据库中所有的信息(比如表、视图、触发器等)都包含在一个文件夹内,方便管理和维护。
4.跨平台:SQLite 目前支持大部分操作系统,不只电脑操作系统,更在众多的手机系统也是能够运行,比如:Android和IOS。
5.多语言接口:SQLite 数据库支持多语言编程接口。
6.安全性:SQLite 数据库通过数据库级上的独占性和共享锁来实现独立事务处理。这意味着多个进程可以在同一时间从同一数据库读取数据,但只能有一个可以写入数据。
小结优缺点:
优点:轻量、高效;动态数据类型;绿色;单一文件;零配置
缺点:并发性能低;SQL功能子集;网络文件
支持的数据类型:
一般数据采用的固定的静态数据类型,而SQLite采用的是动态数据类型,会根据存入值自动判断。SQLite具有以下五种数据类型:
数据类型 | 解析 |
---|---|
NULL | 空值 |
INTEGER | 带符号的整型,具体范围大小取决于存入数字的大小 |
REAL | 浮点数字,存储为8-byte IEEE浮点数 |
TEXT | 字符串文本 |
BLOB | 二进制对象 |
基本的SQL语句:
1.创建表
primary key:主键
autoincrement:自增型变量
if not exists:如果创建的表已存在就不再创建
"create table if not exists 表名 (id integer primary key autoincrement,列名1,列名2,列名3)"
2.增(插入)
"insert into 表名(列名1,列名2,列名3) values(?,?,?)",new Object[]{列名1的值,列名2的值,列名3的值}
3.删
"delete form 表名 where 列名 = ?",new String[]{删除条件}
4.改(更新)
"update 表名 set 修改的列名 = ? where 修改的列名 = ?",new String[]{修改后的值,修改的列名}
5.查
"select * from 表名 where 查询的列名 like ?", new String[]{条件}
6.删除表
drop table if exists 表名
7.清空表
delete from if exists 表名
基本使用:
1.获取SQLiteDataBase对象
SQLiteDatabase database = this.openOrCreateDatabase("family", MODE_PRIVATE, null);
2.创建数据表
database.execSQL("create table family(id integer primary key autoincrement,name,age,relationship)");
3.插入数据
database.esecSQL("insert into family(name,age,relationship values(?,?,?),new Object[]{"Jimyoung",22,"son"})");
database.esecSQL("insert into family(name,age,relationship values(?,?,?),new Object[]{"Papa",47,"father"})");
database.esecSQL("insert into family(name,age,relationship values(?,?,?),new Object[]{"Mama",42,"mother"})");
4.更新数据
database.execSQL("update family set name = ? where name = ?",new String[]{"Boss","Papa"})
5.查询数据
一般通过cursor来得到查询数据并调用rawQuery来查询
Cursor cursor = database.rawQuery("select * from family where name like ?",new String[]{"Jimyoung"});
//实例化一个对象
ArrayList<Map<String,Object list=new ArrayList<();
//循环取值
while(cursor.moveToNext()){
//列按照从0开始算,1指的是name列
String name = cursor.getString(1);
//String name = cursor.getString(cursor.getColumnIndex("name"));或者可以这样写
//实例化map对象
Map<String,Object map = new HashMap<();
//添加值
map.put("name",name);
//将map对象添加list中
list.add(map);
}
6.删除数据
database.execSQL("delete from family where name = ?",new String[]{"Jimyoung"});
一般使用:
一般情况下,会新建一个类继承SQLiteOpenHelper,在其封装增删改查四种方法。在onCreate方法中,写创建表;在onUpgrade方法中,它会根据版本号来更新表;在封装方法时,记得传SQLiteDatabase的对象,因为所有对表的操作都是通过它来的。
public class MySQL extends SQLiteOpenHelper {
public MySQL(Context context, String name,SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
}
@Override
public void onCreate(SQLiteDatabase db) {
//创建表
db.execSQL("create table family (id integer primary key autoincrement, name, age, relationship)");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
{
switch(newVersion){
case 1: db.execSQL(第一个版本的建表语句);
case 2: db.execSQL(第二个版本的建表语句);
case 3: db.execSQL(第三个版本的建表语句);
}
}
使用时:
//实例化封装的SQL类
MySQL mySQL = new MySQL(this, "family.db", null, 1);
//通过mySQL获取SQLiteDatabase对象
SQLiteDatabase database = mySQL.getWritableDatabase();
//之后通过mySQL调用封装方法
二. SharedPreferences存储
简介:
SharedPreferences是Android平台上一个轻量级的存储类,使用键值对的方式来存储数据,用来保存应用的一些常用配置。比如Activity状态,Activity暂停时,将此activity的状态保存到SharedPereferences中;当Activity重载,系统回调方法onSaveInstanceState时,再从SharedPreferences中将值取出。
SharedPreferences提供了java常规的Long、Int、String等类型数据的保存接口。
SharedPreferences类似过去Windows系统上的ini配置文件,但是它分为多种权限,可以全局共享访问,最终是以xml方式来保存,整体效率来看不是特别的高,对于常规的轻量级而言比SQLite要好不少,如果真的存储量不大可以考虑自己定义文件格式。xml处理时Dalvik会通过自带底层的本地XML Parser解析,比如XMLpull方式,这样对于内存资源占用比较好.
数据的四种操作模式:
Context.MODE_PRIVATE:为默认操作模式,代表该文件是私有数据,只能被应用本身访问,在该模式下,写入的内容会覆盖原文件的内容。(只用这个就好,用 0 代替是一样的效果。)
Context.MODE_APPEND:模式会检查文件是否存在,存在就往文件追加内容,否则就创建新文件。(这个好像也废弃了)
MODE_WORLD_READABLE:表示当前文件可以被其他应用读取。(在Android4.2废弃)
MODE_WORLD_WRITEABLE:表示当前文件可以被其他应用写入。(在Android4.2废弃)
SharedPreferences使用:
将数据存储到SharedPreferences中:
要想使用SharedPreferences来存储数据,首先需要获取到SharedPreferences对象。Android中主要提供了3种方法用于得到SharedPreferences对象。
1.Context类中的getSharedPreferences()方法
此方法接收两个参数,第一个参数用于指定SharedPreferences文件的名称,如果指定的文件不存在则会创建一个。SharedPreferences文件都是存放在/data/data/<package name/shared_prefs/目录下的。第二个参数用于指定操作模式。
2.Activity类中的getPreferences()方法
和上面那个方法类似,但只接收一个操作模式参数,因为使用这个方法时会自动将当前活动的类名作为SharedPreferences的文件名。
3.PreferenceManager类中的getDefaultSharedPreferences()方法
这是一个静态方法,它接收一个Context参数,并自动使用当前应用程序的包名作为前缀来命名SharedPreferences文件。
得到SharedPreferences对象后,就可以开始向SharedPreferences文件中存储数据了。主要可以分为以下3步实现:
(1)调用SharedPreferences对象的edit()方法来获取一个SharedPreferences.Editor对象。
(2)向SharedPreferences.Editor对象中添加数据,比如添加一个布尔型数据就可以使用putBoolean()方法,添加一个字符串则使用putString()方法,以此类推。
(3)调用apply()方法将添加的数据提交,从而完成数据存储操作。
SharedPreferences.Editor editor=getSharedPreferences("data",MODE_PRIVATE).edit();
editor.putString("name","Jimyoung");
editor.putInt("age",22)
editor.putBoolean("married",false);
editor.apply();
从SharedPreferences中读取数据:
从SharedPreferences中读取数据很简单。SharedPreferences对象中提供了一系列的 get方法,用于对存储的数据进行读取,每种get方法都对应了SharedPreferences.Editor中的每一种put方法,比如读取一个布尔型数据就使用getBoolean()方法。这些get方法都接收两个参数,第一个参数时键,传入存储数据时使用的键就可以得到相应的值;第二个参数时默认值,即表示当传入的键找不到对应的值时会以什么样的默认值进行返回。
SharedPrefenrences pref = getSharedPreferences("data",MODE_PRIVATE);
String name=pref.getString("name","");
int age=pref.getInt("age",0);
boolean married=pref.getBoolean("married",false);
Log.d("MainActivity","name is "+ name);
Log.d("MainActivity","age is "+ age);
Log.d("MainActivity","married is "+ married);
//运行结果为:
name is Jimyoung
age is 22
married is false
补充:
清除指定数据:
SharedPreferences.Editor editor = userSettings.edit();
editor.remove("KEY");
editor.commit();
清空数据:
SharedPreferences.Editor editor = userSettings.edit();
editor.clear();
editor.commit();
注意:
如果在 Fragment 中使用SharedPreferences 时,需要放在onAttach(Activity activity)里面进行SharedPreferences 的初始化,否则会报空指针 即 getActivity()会可能返回null 。
三. 文件存储
介绍:
文件存储是Android中最基本的一种数据存储方式,它不对存储的内容进行任何的格式化处理,所有数据都是原封不动地保存到文件当中,因而它比较适合用于存储一些简单的文本数据或二进制数据。如果想要使用文件存储方式来保存一些较为复杂的文本数据,就需要定义一套自己的格式规范,这样可以方便以后将数据从文件中重新解析出来。
API
应用私有存储文件:/data/data/<package name/files/目录下。应用删除时,即清空该目录。
//通过context对象获取私有目录:/data/data/packagename/files
context.getFileDir().getPath();
Context对象中文件操作的API及说明:
方法名 | 说明 |
---|---|
openFileInput(String filename) | 打开应用程序私有目录下的的指定私有文件以读入数据,返回一个FileInputStream 对象 |
openFileOutput(String filename,操作模式) | 打开应用程序私有目录下的的指定私有文件以写入数据,返回一个FileOutputStream 对象,如果文件不存在就创建这个文件。 |
fileList() | 搜索应用程序私有文件夹下的私有文件,返回所有文件名的String数组 |
deleteFile(String fileName) | 删除指定文件名的文件,成功返回true,失败返回false |
filename:不能包含路径分隔符“/”,如果文件不存在,Android会自动创建它。创建的文件保存在/data/data/<package name/files目录
操作模式:
常量 | 定义 |
---|---|
MODE_PRIVATE | 默认模式,文件只可以被调用该方法的应用访问。当指定同样文件名的时候,所写入的内容将会覆盖原文件的内容。 |
MODE_APPEND | 如果文件已存在就向该文件的末尾继续写入数据,而不是覆盖原来的数据,不存在就创建新文件。 |
将数据存储到文件中:
private void saveContent() {
String data = et_content.getText().toString();
FileOutputStream out;
BufferedWriter writer = null;
View view = View.inflate(FileActivity.this, R.layout.layout_file, null);
try {
if (!TextUtils.isEmpty(et_content.getText())) {
out = openFileOutput("diary", Context.MODE_PRIVATE);
writer = new BufferedWriter(new OutputStreamWriter(out));
writer.write(data);
} else {
Snackbar.make(view, "没有日记内容可以保存!", Snackbar.LENGTH_SHORT)
.setAction("知道了", new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(FileActivity.this, "开始写日记吧", Toast.LENGTH_SHORT).show();
}
}).show();
}
} catch (IOException e) {
Toast.makeText(FileActivity.this, e.getMessage(), Toast.LENGTH_SHORT).show();
} finally {
try {
if (writer != null) {
writer.close();
}
} catch (IOException e) {
Toast.makeText(FileActivity.this, e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
}
从文件中读取数据:
private String loadContent() {
FileInputStream in;
BufferedReader reader = null;
StringBuilder content = new StringBuilder();
try {
in = openFileInput("diary");
reader = new BufferedReader(new InputStreamReader(in));
String line;
while ((line = reader.readLine()) != null) {
content.append(line);
}
if (!TextUtils.isEmpty(content)){
et_content.setText(content.toString());
et_content.setSelection(content.length());
Toast.makeText(this, "读取成功", Toast.LENGTH_SHORT).show();
}else {
Toast.makeText(this, "没有日记内容", Toast.LENGTH_SHORT).show();
}
} catch (IOException e) {
Toast.makeText(this, e.getMessage(), Toast.LENGTH_SHORT).show();
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
Toast.makeText(this, e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
}
return content.toString();
}
Demo:
大家可以尝试写了一下demo,熟悉一下数据持久化操作。以下为demo截图:
1.png 2.png 3.png
上一篇:Android基础(7)—异步消息处理机制 Handler
下一篇:Android基础(9)—多线程和异步任务
精彩内容不够看?更多精彩内容,请到微信搜索 “危君子频道” 订阅号,每天更新,欢迎大家关注订阅!
微信公众号
网友评论