一、SQlite数据库
1. 简介
-
Android SDK包含了若干有用的SQLite数据库管理类
-
大多都存在于android.database.sqlite包中
-
包中含有许多功能包类:管理数据库的创建和版本信息、 数据库管理以及查询生成类等
-
利用这些包能帮助你生成正确的SQL表达式和查询
-
支持储存数据类型:NULL(空值),INTEGER(int),REAL(8byte浮点数),TEXT(String),BLOB(byte[],可以存储图像信息)
2. 数据库使用
(1)创建数据库
-
使用上下文创建数据库,即构造函数参数需要有Context。
-
创建的类需要继承SQLiteOpenHelper类。
-
需要声明定义数据库名字DB_NAME,版本DB_VRESION。
-
必须重写onCreate,onUpgrade函数,必须声明定义构造函数并super。
-
在onCreate函数中创建数据表,onUpgrade为更新数据库版本。
-
创建数据库访问对象时(即new一个对象),实际上没有创建数据库。 只有调用 getWritableDatabase()或getReadableDatabase() 时才会创建数据库 。
下面的类在数据库中创建了三张表,即“users”,“comments”,“likes”。
public class Mydata extends SQLiteOpenHelper {
private static final String DB_NAME = "mydb.db";
private static final int DB_VRESION = 1;
private static final String UserTable = "users";
private static final String CommentTable = "comments";
private static final String LikesTable = "likes";
//在这个数据库中创建三张表
static final String SQL_CREATE_TABLE1 = "create table " + UserTable + " (username text primary key,"
+ " password text not null, image BLOB);";
static final String SQL_CREATE_TABLE2 = "create table " + CommentTable + " (_id integer primary key autoincrement,"
+ " name text, message text, date text, likes integer);";
static final String SQL_CREATE_TABLE3 = "create table " + LikesTable + " (_id integer primary key autoincrement,"
+ "liker text, date text);";
public Mydata(Context c){
super(c, DB_NAME, null, DB_VRESION);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(SQL_CREATE_TABLE1);
db.execSQL(SQL_CREATE_TABLE2);
db.execSQL(SQL_CREATE_TABLE3);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
// onCreate(db);
}
public String getUserTable() {
return UserTable;
}
public String getCommentTable() {
return CommentTable;
}
public String getLikesTable() {
return LikesTable;
}
}
(2)创建实体类
创建实体类并不是必须的,但是没有实体类并不能很好地对数据库进行操作,比如使用listview来展示数据库中的数据,得先把数据读(查询)到本地来,而创建相关的类来临时保存数据库的数据就很有必要。
比如我们在上面创建了三张表,我们相应地就可以创建三个类,当然要是觉得数据表很简单不一定需要类来保存数据也可以。类需要有以下元素:属性、构造函数、属性Get函数、属性Set函数
例如:我们创建用来保存用户信息的类,当然现实中不可能将密码就这样直接赋值。
public class Users implements Serializable {
byte[] image;
String password;
String name;
public Users(){
password = "";
}
public Users(byte[] image, String password, String name){
this.image = image;
this.password = password;
this.name = name;
}
public void setImage(byte[] image) {
this.image = image;
}
public void setName(String name) {
this.name = name;
}
public void setPassword(String password) {
this.password = password;
}
public byte[] getImage() {
return image;
}
public String getName() {
return name;
}
public String getPassword() {
return password;
}
}
(3)数据操作(增删改查)
-
可以通过execsql函数直接执行SQL命令来完成数据操作,就像我们上面建表一样,但如果嫌麻烦,也可以通过调用SQLiteDatabase类的公共函数insert()、delete()、update()和 query()这四个函数,封装了执行的添加、删除、更新和查询功能的 SQL命令 。具体函数解释可以查看官方文档或者查看实现代码。
-
创建数据库对象
mydata = new Mydata(this);//其实还没创建
-
insert()函数
SQLiteDatabase db = mydata.getWritableDatabase();//真正创建了数据库对象 ContentValues values = new ContentValues();//使用ContentValues声明表中数据 values.put("username", name); values.put("password", password); values.put("image", image); //插入“users”表中,必须保证 values 至少一个字段不为null ,否则出错 db.insert("users", null, values); db.close(); //使用完记得调用close()
-
delete()函数
//比较简单,将数据名称替换掉即可 SQLiteDatabase db = getWritableDatabase(); String whereClause = "_id = ?"; String[] whereArgs = { id.toString() }; //如果后两个参数均为null,则删除所有数据,delete返回一个int,代表删除掉数据量。 db.delete(TABLE_NAME, whereClause, whereArgs); db.close();
-
update()函数
SQLiteDatabase db = getWritableDatabase(); String whereClause = "_id = ?"; String[] whereArgs = { entity.getId().toString() }; ContentValues values = new ContentValues(); values.put("name", entity.getName()); values.put("info", entity.getInfo()); //返回更新的数据量 int rows = db.update(TABLE_NAME, values, whereClause, whereArgs); db.close();
-
query()函数
在Android系统中,数据库查询结果的返回值并不是数据集合的完整拷贝,而是返回数据集的指针,这个指针就是Cursor类;
//注意使用的是getReadableDatabase函数,而不是前面三个的getWritableDatabase。 SQLiteDatabase db = getReadableDatabase(); String selection = "_id = ?"; String[] selectionArgs = { id.toString() }; //如果参数全为null,则返回所有数据 Cursor c = db.query(TABLE_NAME, null, selection, selectionArgs, null,null, null); //在从Cursor中提取数据之前,推荐先测试一下Cursor中的数据数量,避免 在数据获取的过程中产生异常情况。 if (c.moveToFirst()){ User m = new User(c.getInt(0),c.getString(1),c.getString(2)); } c.close(); db.close();
Cursor类支持在查询的数据集合中多种方式移动,并能够获取数据集合的属性名称和序号,Cursor类方法说明如下:
函数 说明 moveToFirst 将指针移动到第一条数据上 moveToNext 将指针移动到下一条数据上 moveToPrevious 将指针移动到上一条数据上 getCount 获取集合的数据数量 getColumnIndexOrThrow 返回指定属性名称的序号,如果属性不存在则产生异常 getColumnName 返回指定序号的属性名称 getColumnNames 返回属性名称的字符串数组 getColumnIndex 根据属性名称返回序号 moveToPosition 将指针移动到指定的数据上 getPosition 返回当前指针的位置
3. 学习过程遇到的坑
- 数据库中的表以及表之间关系设计要合理,如果有学过数据库应该就懂,好的表可以减少很多空间
- 在使用上述四个函数如果表名或者values字段名字出错,是不会报错的,而且不会修改数据库的内容,所以要确保自己不会输入错误。
- 需要修改数据时,要对本地数据以及数据库数据同时修改,如果既有用于listview的数据集合(开始时是从数据库读取出来的),又有数据库数据,千万不要先修改本地数据再修改数据库数据,因为当你修改完本地数据的时候,你再来修改数据库数据,可能会借助本地数据的下标来进行数据的条件限定,但因为已经先修改了本地数据,所以此时数据不是一一对应的。所以要先修改数据库再修改本地数据。
二、ContentProvider数据分享
不详讲,这个还没学会。
这里只举一个使用数据提供者的例子,你在某个App已经拥有一个用户名,如何获取通讯录(另一个App)中用户的电话号码。
-
在AndroidManifest.xml文件添加权限,声明读取通讯录的权限
<uses-permission android:name="android.permission.READ_CONTACTS"/>
-
使用getContentResolver方法查询相应用户名
Cursor cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,null, ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " = \"" + username + "\"", null, null);
-
读取查询到的号码(得确保不为空)
cursor.moveToFirst(); String number = "\nPhone: "; do { number += cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)) + " "; } while (cursor.moveToNext());