日期:2014-05-16  浏览次数:20507 次

Android笔记: databases and Content Providers
Databases and Content Providers

这一章的主要内容有
创建数据库,使用SQLite
使用Content Providers分享应用数据
查询Content Providers
使用Cursors和Content Values同Content Providers交互
数据库设计的考虑
介绍本地Content Providers
使用Contact Content Provider

(一)介绍android的数据库
android 的结构化数据持久是由SQLite数据库和Content Providers来提供的。
使用SQLite可以为应用创建独立的关系型数据库。用这些数据库可以存储和管理复杂的结构化的应用数据。
android数据库保存在/data/data/<package_name>/databases这个路径下面。默认只有创建某个数据库的应用可以访问这个数据库。
Content Providers 提供了发布数据,使用数据的接口,基于一个使用content://模式的简单的URI地址模型。我们可以借此解除应用层和数据层的耦合。
被分享的Content Providers可以被查询,修改,删除,也可以被添加新的记录。如果有相应的许可,一个应用添加,删除,修改任何其他应用的数据,包括android自带的数据库。
许多android自带的数据库可以作为Content Providers被第三方应用访问,例如电话簿,媒体库等。
当然你也可以把你自己的应用的数据发布成Content Providers,这样新的应用也可以和合并和扩展你的数据。

(二)介绍SQLite
SQLite是个受到好评的关系型数据库管理系统。它的特点有
1)开源
2)符合标准
3)轻量
4)单层次

android的SQLite只是一个库而不是一个单独的进程,每一个SQLite数据库都是创建这个数据库的应用的组成部分,所以也减少了外部依赖,减少了延时,简化了事物的锁和同步。
SQLite不同于通常的关系型数据库的一点是,每个列并不被要求是一个单一的类型,而是针对每行可以单独规定值的类型。

(三)CURSORS 和 CONTENT VALUES
ContentValues 用来向表里插入一条新的记录。
Android的查询会返回一个Cursor对象。

Cursor提供的部分功能如下:
moveToFirst
moveToNext
moveToPrevious
getCount
getColumnIndexOrThrow 给出某个列名对应的下标(如果该列名不存在会抛出异常)getColumnName
getColumnNames
moveToPosition
getPosition

可以在Activity中使用startManagingCursor和stopManagingCursor方法来管理Cursor的生命周期。


(四)使用SQLite DATABASES
SQLiteOpenHelper是一个抽象类,主要作用是创建,打开,升级数据库。譬如用户在继承SQLiteOpenHelper的类中重写onUpgrade方法时可以把现有数据库的数据迁移到新版本的数据库。
调用getReadableDatabase 或者 getWritableDatabase 方法可以打开并且返回一个可读或者可写的数据库实例。

当然也可以不使用SQLiteOpenHelper来打开数据库,可以先使用openOrCreateDatabase方法来创建一个数据库,再使用execSQL方法来创建这个数据库中的表等对象。
SQLiteOpenHelper方法返回的是一个SQLiteDatabase对象, 数据库操作都要用到SQLiteDatabase类。

SQLiteDatabase中的query,insert,update,delete方法用于数据的查询,插入,修改和删除,而Cursor的moveToFirst和moveToNext等方法可以实现对查询结果的遍历。

设计数据库时,两点需要注意的是:
不要把文件保存到表里,最好是保存路径,譬如一个URI。
尽可能用自增长唯一索引来作一个键,用Content Provider的时候唯一的主键字段是必须的。



(五)创建一个CONTENT PROVIDER
创建一个新的Content Provider需要继承ContentProvider这个抽象类,并且重写onCreate方法。
需要一个 public static CONTENT_URI 来返回这个PROVIDER的URI。为了确保唯一性,这个URI的命名可以用类似包名的形式,例如
content://com.paad.provider.myapp/elements

Content URIs可以表示两种格式,譬如上面这个URI代表某个类型所有的值,而下面这个加了行号的URI则表示一个单独的记录

content://com.paad.provider.myapp/elements/5

对于这两种格式,可以创建一个UriMatcher来区分:
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI("com.paad.provider.myApp", "items", ALLROWS);
uriMatcher.addURI("com.paad.provider.myApp", "items/#", SINGLE_ROW);


当得到一个uri的时候,就可以使用UriMatcher来判断,这个uri到底是所有记录还是单条记录了:

switch (uriMatcher.match(uri)) {
case SINGLE_ROW :
// TODO: Modify selection based on row id, where:
// rowNumber = uri.getPathSegments().get(1));
}


然后是重写delete, insert, update 和 query 方法, 这些方法以后会被Content Resolver用来访问数据,他们只是一个接口,并不是只针对数据库的(从名字上看有可能让人误解),其实除了可以访问SQLite的数据,也可以访问应用的其他变量。

重写getType,返回MIME type。

@Override
public String getType(Uri _uri) {
switch (uriMatcher.match(_uri)) {
case ALLROWS: return "vnd.paad.cursor.dir/myprovidercontent";
case SINGLE_ROW: return "vnd.paad.cursor.item/myprovidercontent";
default: throw new IllegalArgumentException("Unsupported URI: " + _uri);
}
}


注册你的Provider
在manifest文件用authorities来指定基础的URI
<provider android:name="MyProvider"
android:authorities="com.paad.provider.myapp"/>




(六)使用CONTENT PROVIDERS
每个application Context都包含一个ContentResolver实例,可以用如下方法来获得。

ContentResolver cr = getContentResolver();


ContentResolver
用来查询和修