安卓中有五种数据存储模式:
1.sharedpreferences : 一般用来存放少量配置信息,通过xml来保存,标签来取。
2.文本文档:这和就是把数据以字符串的形式存放在文本文档上。
3.content provider : 这种是通过内容提供者暴露数据,请求数据的一方可以通过约定好的Uri规则来访问数据。
4.网络存储:就是上传到网络上,像一些云服务–百度云。
5.SQLite:轻量型的数据库,通常用来存放大量的,复杂的,结构化的数据。
我们今天要介绍的就是第五种,sqlite数据存储方式。
要操作安卓系统中自带的数据库,我们要首先要继承SQLiteOpenHelper这个类,我们只有在继承这个类才能拿到数据库的对象实例。在这里我简单的继承了一下这个类,如下:
public class DBHelper extends SQLiteOpenHelper {
// 构造方法
public DBHelper(Context context) {
super(context, "Person.db", null, 1);
}
//在第一次创建数据库的时候调用,之后将不再调用这个方法。
@Override
public void onCreate(SQLiteDatabase db) {
String sql = "CREATE TABLE person( id VARCHAR PRIMARY KEY , name VARCHAR , age VARCHAR)";
db.execSQL(sql);
}
//数据库升级的时候调用的方法。
@Override
public void onUpgrade(SQLiteDatabase arg0, int arg1, int arg2) {
}
}
通过上面简单的继承,我们就可以通过构造方法拿到这个数据库对象了,接下来就是对数据库的操作了。温馨提示:操作数据库之前,一定要添加权限。
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
不过有时候我们需要在程序初始的时候就带入大量的数据,代码中放入大量的sql显然是不明智的。我们可以在PC上把数据拷过来,然后程序中复制到项目的数据库目录下面就可以了,如果这样的话,我们就应该把onCreate中的代码去掉,使用我们assets里面存放的数据库文件
/**
*拷贝数据库文件到项目的数据库目录下
*/
public static boolean copyDatabase(Context context, String dbName) {
boolean ok = false;
String directory = getDatabasePath(context);
String filePath = directory + dbName;
File file = new File(directory);
if (!file.exists()) {
file.mkdir();
}
File dbFile = new File(filePath);
if (dbFile.exists()) {
return true;
} else {
InputStream is = null;
OutputStream os = null;
try {
is = context.getAssets().open(dbName);
os = new FileOutputStream(dbFile);
byte[] buffer = new byte[1024 * 8];
int len = -1;
while ((len = is.read(buffer)) > 0) {
os.write(buffer, 0, len);
}
os.flush();
ok = true;
is.close();
os.close();
} catch (Exception e) {
ok = false;
Log.i("com.cvil.sqlite.test", "asset file " + dbName
+ " not exits !");
}
}
return ok;
}
private static String getDatabasePath(Context context) {
File defaultDBFile = context.getDatabasePath("d");
String path = defaultDBFile.getPath();
return path.substring(0, path.length() - 1);
}
这段代码应该程序启动的时候就执行,也就是application类里面。在application类里面直接调用静态方法。
DBHelper.copyDatabase(this, "example.db") ;
这些操作已经全部写在PersonDao这个类里面了,下面我们就开始分析这个类吧。对数据库的操作,始终都离不开增删改查,基本都是这些操作。不管做什么,我们都必须先拿到这个数据库实例:
public PersonDao(Context context) {
helper = new DBHelper(context);
}
我们直接在构造方法里面创建DBHelper实例,通过SQLiteDatabase sdb = helper.getWritableDatabase() ;就可以拿到数据库了。
1.首先我们看查询方法。在这个类里面我们定义了两个全局变量,免得查询的时候传参麻烦,所以直接通过set方法给全局变量sql和parameters进行赋值查询。
//添加参数
public void addParameters(String parameter) {
parameters.add(parameter);
}
/**
* 查询
*
* @return
*/
public JSONArray query() {
SQLiteDatabase sdb = helper.getReadableDatabase();
String[] args = new String[] {};
JSONArray array = new JSONArray();
try {
if (StringUtils.isEmpty(sql)) {
throw new Exception(NO_SQL_EXCEPTION_NAME);
}
if (parameters != null && parameters.size() > 0) {
args = parameters.toArray(new String[parameters.size()]);
}
Cursor cursor = sdb.rawQuery(sql, args);
JSONObject jsonObject = null;
if (cursor != null && cursor.getCount() > 0) {
String[] columns = cursor.getColumnNames();
for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor
.moveToNext()) {
jsonObject = new JSONObject();
for (String column : columns) {
String tempValue = cursor.getString(cursor
.getColumnIndex(column));
if (StringUtils.isNotEmpty(tempValue)) {
jsonObject.put(column, cursor.getString(cursor
.getColumnIndex(column)));
} else {
jsonObject.put(column, "");
}
}
array.put(jsonObject);
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
sdb.close();
}
return array;
}
上面的代码中,Cursor cursor = sdb.rawQuery(sql, args);这一句是核心。里面的参数sql就是我们定义的全局变量,args是定义的全局变量转化而来,这个参数的含义是按顺序来替换sql中占位符”?”,也就是说,我们在setSql的时候,一定要按照顺序来addParameters,否则数据就会乱。
2.有了查询这个基本操作之后,其他操作就都变得很轻松了,我们其他很多操作都需要这个方法的辅助,我们接下来就看一下怎么获取表的详细信息。一个表的主键非常重要,因为在操作表的过程中,我们可能很多地方需要用到主键,我们先来获取一下主键,在这之前,你要熟悉“PRAGMA TABLE_INFO(table_name)”这个sql,这个可以拿到表的所有相关信息,字段,类型,是否为空,主键,外键等等。这里我们只关心主键和字段名。
/**
* 获取表的新信息。
*
* @param tableName
* @return
*/
public JSONArray getTableInfo(String tableName) {
this.sql = "PRAGMA TABLE_INFO ('" + tableName + "') ";//设置执行需要的sql
clearParameters(); //没有占位符,不需要参数,清空参数。
return query();//执行查询。
}
我们通过上面的代码就拿到了这个表的基本信息,由JsonArray对象返回。我们通过解析这个返回的表信息就可以拿到主键字段名了。
/**
* 获取主键
*
* @param tableName
* @return
*/
public String getPrimaryKey(String tableName) {
String result = "";
try {
JSONArray tableInfo = getTableInfo(tableName);
if (tableInfo != null && tableInfo.length() > 0) {
for (int i = 0; i < tableInfo.length(); i++) {
JSONObject jsonItem = tableInfo.getJSONObject(i);
String field = jsonItem.getString("name");
String pkValue = jsonItem.getString("pk");
if (pkValue.equals("1")) {
result = field;
break;
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
我们对拿到的JsonArray进行遍历,在“PRAGMA TABLE_INFO(table_name)”执行拿到的结果集中,每一项都会有pk和name这两个字段(因为我们现在只关心这两个),如果这个字段是主键的话,pk对应的值就是1,所以我们在看到某个字段的pkValue对应为1的时候,我们返回name对应的值,这个值就是他对应的字段了。
3.查询做的差不多了,进入主要部分了,更新和插入这个比较麻烦,有存在主键相同和不相同的情况,我们需要分别操作,不过在这之前,我们先来了解sql的插入和更新语法,有助于在后面的sql组装的理解:
插入:INSERT INTO TABLE ( PRIMARY_KEY , COLUMN_A , COLUMN_B , COLUMN_C ) VALUES ( PRIMARY_KEY_VALUE , VALUE_A ,VALUE_B ,VALUE_C ) ;
更新:UPDATE TABLE SET COLUMN_A = ‘VALUE_A’ ,COLUMN_B = ‘VALUE_B’ ,COLUMN_C = ‘VALUE_C’ WHERE PRIMARY_KEY = ‘PRIMARY_KEY_VALUE’;
/**
* 组装插入语句
* @param json 插入的数据参数
* @param tableName 表名
* @param primaryKey 主键
* @return 执行的sql语句
*/
private String createInsertSql(JSONObject json, String tableName,String primaryKey) {
Iterator<String> keys = json.keys();
String whereColumns = "";
String whereArgs = "";
while (keys.hasNext()) {
String key = keys.next();
if(key.equals(primaryKey)){
continue ;
}
whereColumns += "," + key;
whereArgs += ",'" + json.optString(key) + "'";
}
return "INSERT INTO " + tableName + "(" + whereColumns.substring(1)
+ ") VALUES (" + whereArgs.substring(1) + ")";
}
/**
* 组装更新语句
* @param json 插入的数据参数
* @param tableName 表名
* @param primaryKey 主键
* @return 执行的sql语句
*/
private String createUpdateSql(JSONObject json, String tableName,
String primaryKey) {
Iterator<String> keys = json.keys();
String where = "";
String whereColumns = "";
while (keys.hasNext()) {
String key = keys.next();
if (key.equals(primaryKey)) {
where += key + " = '" + json.optString(key) + "'";
} else {
whereColumns += "," + key + "='" + json.optString(key) + "'";
}
}
return "UPDATE " + tableName + " SET " + whereColumns.substring(1)+" WHERE " + where;
}
首先将要插入的数据参数json的key放入迭代器进行循环遍历。在创建插入语句和更新语句的时候,对于主键的处理是不一样的,在插入的时候,我们是没有把主键撞到sql里面的,在更新那,我们把主键作为where条件来使用,因为我们要唯一确定一条更新的记录,我们必须通过主键来确定。在代码里面,我们再也不用担心语句的插入了,存在这条记录,他会自己去更新,不存在就插入,而实现这个判断的是:
/**
* 主键值
*
* @return
*/
private boolean isExist(String key) {
boolean isExist = false;
this.sql = "SELECT * FROM person WHERE id = '" + key + "' ";
clearParameters();
JSONArray array = query();
if (array != null && array.length() > 0) {
isExist = true;
}
return isExist;
}
通过这个来判断是否存在主键值对应的数据。
/**
* 插入
*
* @param json
*/
public void insert(String tableName, JSONObject json) {
String primaryKey = "";
try {
JSONArray tableFieldInfo = getTableInfo(tableName);
if (tableFieldInfo != null && tableFieldInfo.length() > 0) {
for (int i = 0; i < tableFieldInfo.length(); i++) {
JSONObject jsonItem = tableFieldInfo.getJSONObject(i);
String pkValue = jsonItem.getString("pk");
String field = jsonItem.getString("name");
if (pkValue.equals("1")) {
if (StringUtils.isEmpty(json.getString(field))) {
throw new Exception("sql illeagl , primary key "
+ field + " is null .");
}
primaryKey = field;
}
}
String sql = "";
if (isExist(json.getString(getPrimaryKey(tableName)))) {
sql = createUpdateSql(json, tableName, primaryKey);
} else {
sql = createInsertSql(json, tableName, primaryKey);
}
executeSql(sql);
}
} catch (Exception e) {
e.printStackTrace();
}
}
在上面的执行过程中注意异常的抛出,这样我们很容易的就可以在调试中定位到错误。
3.把更新和插入一起将了,现在就剩下删除了,这个其实也是最简单了的 。
/**
* 删除主键值为 “id”的记录
* @param id 待删除记录的主键值。
*/
public void delete(String id) {
if (isExist(id)) {
SQLiteDatabase sdb = helper.getWritableDatabase();
this.sql = "DELETE FROM person WHERE id = ? ";
sdb.execSQL(sql, new String[] { id });
sdb.close();
} else {
try {
throw new Exception("data with id = " + id + " not exists ");
} catch (Exception e) {
e.printStackTrace();
}
}
}
轻松搞定。下面附上activity的代码:
package com.example.sqlitetest;
import org.json.JSONArray;
import org.json.JSONObject;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.TextView;
public class MainActivity extends Activity implements OnClickListener{
private PersonDao dao ;
private TextView textView ;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.query).setOnClickListener(this) ;
findViewById(R.id.insert).setOnClickListener(this) ;
findViewById(R.id.delete).setOnClickListener(this) ;
findViewById(R.id.getPrimaryKey).setOnClickListener(this) ;
textView = (TextView) findViewById(R.id.text) ;
dao = new PersonDao(this) ;
}
public void onClick(View v) {
String sql ;
switch (v.getId()) {
case R.id.query:
sql = "SELECT * FROM person " ;
dao.setSql(sql);
dao.clearParameters() ;
JSONArray array = dao.query() ;
textView.setText(String.valueOf(array)) ;
break;
case R.id.insert:
JSONObject json = new JSONObject() ;
try{
json.put("id", String.valueOf(System.currentTimeMillis()));
json.put("name", "caoweiwww");
json.put("age", "2c");
dao.insert(PersonDao.TABLE_NAME,json) ;
}catch (Exception e) {
e.printStackTrace() ;
}
break ;
case R.id.delete:
dao.delete("4356fd");
break ;
case R.id.getPrimaryKey:
String primaryKey = dao.getPrimaryKey("person");
if(StringUtils.isNotEmpty(primaryKey)){
textView.setText(primaryKey);
}
break ;
}
}
}
//以下是PersonDao完整代码
package com.example.sqlitetest;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.json.JSONArray;
import org.json.JSONObject;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
public class PersonDao {
private DBHelper helper;
private String sql;
public static final String TABLE_NAME = "person";
private List<String> parameters = new ArrayList<String>();
private static final String NO_SQL_EXCEPTION_NAME = "sql is illeagl , set the sql please .";
public PersonDao() {
this(null, null);
}
public PersonDao(String sql) {
this(sql, null);
}
public PersonDao(String sql, List<String> parameters) {
this.sql = sql;
this.parameters = parameters;
}
public void setSql(String sql) {
this.sql = sql;
}
public void addParameters(String parameter) {
parameters.add(parameter);
}
public void setParameters(List<String> parameters) {
this.parameters = parameters;
}
public PersonDao(Context context) {
helper = new DBHelper(context);
}
/**
* 插入
*
* @param json
*/
public void insert(String tableName, JSONObject json) {
String primaryKey = "";
try {
JSONArray tableFieldInfo = getTableInfo(tableName);
if (tableFieldInfo != null && tableFieldInfo.length() > 0) {
for (int i = 0; i < tableFieldInfo.length(); i++) {
JSONObject jsonItem = tableFieldInfo.getJSONObject(i);
String pkValue = jsonItem.getString("pk");
String field = jsonItem.getString("name");
if (pkValue.equals("1")) {
if (StringUtils.isEmpty(json.getString(field))) {
throw new Exception("sql illeagl , primary key "
+ field + " is null .");
}
primaryKey = field;
}
}
String sql = "";
if (isExist(json.getString(getPrimaryKey(tableName)))) {
sql = createUpdateSql(json, tableName, primaryKey);
} else {
sql = createInsertSql(json, tableName, primaryKey);
}
executeSql(sql);
}
} catch (Exception e) {
e.printStackTrace();
}
}
private void executeSql(String sql) {
SQLiteDatabase sdb = helper.getWritableDatabase();
sdb.execSQL(sql);
sdb.close();
}
public void executeBatchSql(String[] sqls) {
SQLiteDatabase sdb = helper.getWritableDatabase();
for (String sql : sqls) {
sdb.execSQL(sql);
}
sdb.close();
}
/**
* 删除主键值为 “id”的记录
* @param id 主键值。
*/
public void delete(String id) {
if (isExist(id)) {
SQLiteDatabase sdb = helper.getWritableDatabase();
this.sql = "DELETE FROM person WHERE id = ? ";
sdb.execSQL(sql, new String[] { id });
sdb.close();
} else {
try {
throw new Exception("data with id = " + id + " not exists ");
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 组装插入语句
*
* @param json
* 插入的数据参数
* @param tableName
* 表名
* @param primaryKey
* 主键
* @return 执行的sql语句
*/
private String createInsertSql(JSONObject json, String tableName,
String primaryKey) {
Iterator<String> keys = json.keys();
String whereColumns = "";
String whereArgs = "";
while (keys.hasNext()) {
String key = keys.next();
if (key.equals(primaryKey)) {
continue;
}
whereColumns += "," + key;
whereArgs += ",'" + json.optString(key) + "'";
}
return "INSERT INTO " + tableName + "(" + whereColumns.substring(1)
+ ") VALUES (" + whereArgs.substring(1) + ")";
}
/**
* 组装更新语句
*
* @param json
* 插入的数据参数
* @param tableName
* 表名
* @param primaryKey
* 主键
* @return 执行的sql语句
*/
private String createUpdateSql(JSONObject json, String tableName,
String primaryKey) {
Iterator<String> keys = json.keys();
String where = "";
String whereColumns = "";
while (keys.hasNext()) {
String key = keys.next();
if (key.equals(primaryKey)) {
where += key + " = '" + json.optString(key) + "'";
} else {
whereColumns += "," + key + "='" + json.optString(key) + "'";
}
}
return "UPDATE " + tableName + " SET " + whereColumns.substring(1)
+ " WHERE " + where;
}
/**
* 主键值
*
* @return
*/
private boolean isExist(String key) {
boolean isExist = false;
this.sql = "SELECT * FROM person WHERE id = '" + key + "' ";
clearParameters();
JSONArray array = query();
if (array != null && array.length() > 0) {
isExist = true;
}
return isExist;
}
/**
* 获取主键
*
* @param tableName
* @return
*/
public String getPrimaryKey(String tableName) {
String result = "";
try {
JSONArray tableInfo = getTableInfo(tableName);
if (tableInfo != null && tableInfo.length() > 0) {
for (int i = 0; i < tableInfo.length(); i++) {
JSONObject jsonItem = tableInfo.getJSONObject(i);
String field = jsonItem.getString("name");
String pkValue = jsonItem.getString("pk");
if (pkValue.equals("1")) {
result = field;
break;
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
/**
* 获取主键列表
*
* @param tableName
* @return
*/
public List<String> getPrimaryKeyList(String tableName) {
List<String> result = new ArrayList<String>();
try {
JSONArray tableInfo = getTableInfo(tableName);
if (tableInfo != null && tableInfo.length() > 0) {
for (int i = 0; i < tableInfo.length(); i++) {
JSONObject jsonItem = tableInfo.getJSONObject(i);
String field = jsonItem.getString("NAME");
String pkValue = jsonItem.getString("PK");
if (pkValue.equals("1")) {
result.add(field);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
/**
* 获取表的各字段
*
* @param tableName
* 表名
* @return
*/
public List<String> getTableFieldList(String tableName) {
List<String> result = new ArrayList<String>();
try {
JSONArray tableInfo = getTableInfo(tableName);
if (tableInfo != null && tableInfo.length() > 0) {
for (int i = 0; i < tableInfo.length(); i++) {
JSONObject jsonItem = tableInfo.getJSONObject(i);
String field = jsonItem.getString("NAME");
result.add(field);
}
}
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
/**
* 获取表的新信息。
*
* @param tableName
* @return
*/
public JSONArray getTableInfo(String tableName) {
this.sql = "PRAGMA TABLE_INFO ('" + tableName + "') ";
clearParameters();
return query();
}
/**
* 清除参数
*/
public void clearParameters() {
parameters.clear();
}
/**
* 查询
*
* @return
*/
public JSONArray query() {
SQLiteDatabase sdb = helper.getReadableDatabase();
String[] args = new String[] {};
JSONArray array = new JSONArray();
try {
if (StringUtils.isEmpty(sql)) {
throw new Exception(NO_SQL_EXCEPTION_NAME);
}
if (parameters != null && parameters.size() > 0) {
args = parameters.toArray(new String[parameters.size()]);
}
Cursor cursor = sdb.rawQuery(sql, args);
JSONObject jsonObject = null;
if (cursor != null && cursor.getCount() > 0) {
String[] columns = cursor.getColumnNames();
for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor
.moveToNext()) {
jsonObject = new JSONObject();
for (String column : columns) {
String tempValue = cursor.getString(cursor
.getColumnIndex(column));
if (StringUtils.isNotEmpty(tempValue)) {
jsonObject.put(column, cursor.getString(cursor
.getColumnIndex(column)));
} else {
jsonObject.put(column, "");
}
}
array.put(jsonObject);
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
sdb.close();
}
return array;
}
}