Android数据存储与IO之四(SQLite)
有些时候,我们会有部分的以某种固定格式存在的数据需要保存在手机内并且需要增删改查,这时候使用File和SharePreferences就显得太过与麻烦,为了解决这类问题,Android集成了一个轻量级的数据库SQLite,其作为一个嵌入式的数据库引擎,适用于资源有限的设备上适量数据存储,从本质上来看,SQLite的操作方式只是一种更为便捷的文件操作,当用户打开一个SQLite数据库时,其实只是打开一个文件准备读写,因而对于大量的用户的并发储存,SQLite并不适用,毕竟手机还是手机,它的储存能力计算能力都不足以让其成为一个服务器的角色。
一般来说使用数据库分为三步 第一是加载驱动 第二是连接数据库,第三是操作数据库,但是在安卓中则不用那么麻烦,Android系统中提供了一个SQLiteOpenHelper抽象类其中封装了一些驱动,该类用于对数据库进行处理,该类中有三个常用方法:
onCreate 数据库创建时执行(第一次连接获取数据库对象执行)
onUpgrate 数据库版本号改变时执行
onOpen 数据库每次打开时执行,在onCreate和onUpgrate 之后执行
在操作过程中,建议将数据库,数据库中存储的数据类型,数据库的操作方法,以及展示界面等类分包存储,首先建立数据库,先新建一个以.db结尾的包并在其中新建一个继承了SQLiteOpenHelper抽象类类的类,继承后首先要写出构造方法:
PersonSQLiteOpenHelper(Context context 上下文
, String name 要建立的数据库的名称,不需加入绝对路径,需加入.db的后缀
, CursorFactory factory 游标工程 一般情况下为null
, int version 数据库的版本号,不能小于1
)
接下来就是创建一张表,说到创建表就不得不提到SQLite中的数据类型,SQLite的数据类型为无类型,你可以保存任何格式的数据到任何表的任何列中而不必在意其定义时到底定义该列为何种数据类型,因为SQLite在存储时将所有数据都以字符串的形式存储,只有一个特别interger primary key只能存储64位的整数,SQLite同时支持其他数据格式例如NULL,VARCHAR(字符类型),TEXT(文本类型),INTEGER(整数类型)等等,但是我们在创建表的时候依然要指明每一列的数据类型为的是防止在取出数据时因为不知道该处的数据类型而导致强制转换出错。
SQLite支持绝大部分SQL92语法,也允许开发者使用SQL语言操作数据库中的数据,SQLiteDatabase的execSQL方法可以执行任何SQL语句包括带占位符的语句
比如这样的创建语句 :create table person(_id integer primary key,name varchar(10),age integer);在写好后,我们可以在另外一个软件SQLite Expert Personal 3中执行一下来判断我们的语句是否正确。确认正确后,我们通过XX.execSQL(“create table person(_id integer primary key,name varchar(10),age integer);”)其中xx为数据库名称来执行该语句。同理,我们可以以此方式执行其他SQL语句,值得一提的是execSQL允许使用占位符,比如在下面的情况中,我们需要完成一个插入函数,但是执行execSQL(“insert into person(name,age)valus(‘lisi’,19);”)明显是不合适的,因为我们不可能将插入人的姓名和年龄写死,在这里就要使用占位符,具体方法是将你要写入变量位置的量用?代替,并在SQL语句后加上一个按照前面?顺序排列的数组,比如刚才的语句就可以改成execSQL(“insert into person(name,age)valus(?,?);”,new Object[]{name,age})。另外,事实上SQLite为我们提供了各种增删改查的方法,但是事实上这倒是有些鸡肋,毕竟SQL语法是基本功。下面就是完成一个基本的自定义的增删改查的函数操作。
首先我们新建立一个以.dao为结尾的包,并在包中新建操作类,因为我们想要获取表就需要用到该表对应的SQLiteOpenHelper对象,所以首先我们要获得已经创建好的SQLiteOpenHelper子类的对象,接下来在每一个函数中,我们都需要使用xx.getWritableDatabase()方法或者xx.getReadableDatabase()获得一个可读写或者仅可读的用于操作数据库的SQLiteDatabase实例(其中xx是SQLiteOpenHelper子类的对象)。并在执行SQL语句之前先使用if(xx.isOpen())来判断数据库是否可用(其中xx为获得的SQLiteDatabase实例),当程序第一次调用getWritableDatabase()或者getReadableDatabase()方法后,SQLiteOpenHelper会缓存已经获得SQLiteDatabase实例,SQLiteDatabase实例在正常情况下会维持数据库的打开状态,一旦缓存,多次调用getWritableDatabase()或者getReadableDatabase()方法得到的都是同一个SQLiteDatabase实例,所以函数写完后我们需要使用close方法关闭数据库。
唯一一个特殊的是查询函数,因为我们查询过程中要返回数据而单纯的SQL语句无法完成这一点,这里就要用到rawQuery函数,这个函数返回的是执行rawQuery函数后面()里的SQL语句后的指向第0行的Cursor对象,我们可以通过控制这个Cursor对象的移动来获得任意一个位置的数据,Cursor提供了如下方法:
Boolean moveToFirst()将指针移到第一行,成功返回true
Boolean moveToLast()将指针移到最后一行,成功返回true
Boolean moveToNext()将指针移到下一行,成功返回true
Boolean moveToPosition(int position)将指针移到指定行,成功返回true
Boolean moveToPrevious()将指针移到上一行,成功返回true
下面是一个英文单词本的实例,该单词本可以添加生词及其详解并可以通过模糊查找关键词的方式进行查找。
MainAcyivity:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dao = new Test12Dao(this);
help = new PersonSQLiteOpenHelper(this);
word = (EditText) findViewById(R.id.word);
detail = (EditText) findViewById(R.id.detail);
add = (Button) findViewById(R.id.add);
search = (Button) findViewById(R.id.search);
key = (EditText) findViewById(R.id.key);
output = (TextView) findViewById(R.id.output);
add.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
if (dao.insert(new Test12(word.getText().toString(), detail
.getText().toString()))) {
Toast.makeText(MainActivity.this, "成功添加", Toast.LENGTH_LONG);
} else {
Toast.makeText(MainActivity.this, "未成功添加",
Toast.LENGTH_LONG);
}
}
});
search.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
output.setText(dao.search(key.getText().toString()));
}
});
}
进行插入与查找操作的类:
public class Test12Dao {
private PersonSQLiteOpenHelper help;
public Test12Dao(Context context) {
help = new PersonSQLiteOpenHelper(context);
}
public Boolean insert(Test12 test) {
SQLiteDatabase db = help.getWritableDatabase();
if (db.isOpen()) {
db.execSQL("insert into test12(word,detail) values(?,?)",
new Object[] { test.getName(), test.getDetail() });
db.close();
return true;
}
return false;
}
public String search(String key) {
SQLiteDatabase db = help.getWritableDatabase();
List<Test12> test12 = null;
if (db.isOpen()) {
Cursor cursor = db
.rawQuery(
"select _id,word,detail from test12 where word like ? or detail like ?",
new String[] { "%" + key + "%", "%" + key + "%" });
if (cursor != null && cursor.moveToFirst()) {
test12 = new ArrayList<Test12>();
int id;
String word;
String detail;
while (cursor.moveToNext()) {
id = cursor.getInt(0);
word = cursor.getString(1);
detail = cursor.getString(2);
Test12 test = new Test12(word, detail);
test12.add(test);
}
db.close();
}
}
return test12.toString();
}
}
数据库中的值的类型类:
public class Test12 {
private int _id;
private String name;
private String detail;
public int get_id() {
return _id;
}
public void set_id(int _id) {
this._id = _id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDetail() {
return detail;
}
public void setDetail(String detail) {
this.detail = detail;
}
public Test12( String name, String detail) {
super();
this.name = name;
this.detail = detail;
}
@Override
public String toString() {
return "Test12 [_id=" + _id + ", name=" + name + ", detail=" + detail
+ "]";
}
SQLiteOpenHelper子类:
public class PersonSQLiteOpenHelper extends SQLiteOpenHelper {
public PersonSQLiteOpenHelper(Context context) {
super(context, "test12.db", null, 1);
// TODO Auto-generated constructor stub
}
@Override
public void onCreate(SQLiteDatabase db) {
String sql="create table test12(_id integer primary key autoincrement,word,detail);";
db.execSQL(sql);
}
@Override
public void onUpgrade(SQLiteDatabase arg0, int arg1, int arg2) {
// TODO Auto-generated method stub
}
}