本章节翻译自《Beginning-Android-4-Application-Development》,如有翻译不当的地方,敬请指出。
原书购买地址http://www.amazon.com/Beginning-Android-4-Application-Development/dp/1118199545/
在Android平台上创建ContentProvider,相对而言是很容易的。你所需做的就是继承ContentProvider这个抽象类,然后重新它里面的各种方法。
下面将介绍如何创建一个ContentProvider,用来存储一些图书的信息。
1. 使用Eclipse创建一个工程,ContentProviders。
2. 新建一个名为BooksProvider类。
3. BooksProvider.java中的代码。
public class BooksProvider extends ContentProvider
{
static final String PROVIDER_NAME =
"net.manoel.provider.Books";
static final Uri CONTENT_URI =
Uri.parse("content://"+ PROVIDER_NAME + "/books");
static final String _ID = "_id";
static final String TITLE = "title";
static final String ISBN = "isbn";
static final int BOOKS = 1;
static final int BOOK_ID = 2;
private static final UriMatcher uriMatcher;
static{
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(PROVIDER_NAME, "books", BOOKS);
uriMatcher.addURI(PROVIDER_NAME, "books/#", BOOK_ID);
}
//---for database use---
SQLiteDatabase booksDB;
static final String DATABASE_NAME = "Books";
static final String DATABASE_TABLE = "titles";
static final int DATABASE_VERSION = 1;
static final String DATABASE_CREATE =
"create table " + DATABASE_TABLE +
" (_id integer primary key autoincrement, "
+ "title text not null, isbn text not null);";
private static class DatabaseHelper extends SQLiteOpenHelper
{
DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db)
{
db.execSQL(DATABASE_CREATE);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion,
int newVersion) {
Log.w("Content provider database",
"Upgrading database from version " +
oldVersion + " to " + newVersion +
", which will destroy all old data");
db.execSQL("DROP TABLE IF EXISTS titles");
onCreate(db);
}
}
@Override
public int delete(Uri arg0, String arg1, String[] arg2) {
// arg0 = uri
// arg1 = selection
// arg2 = selectionArgs
int count=0;
switch (uriMatcher.match(arg0)){
case BOOKS:
count = booksDB.delete(
DATABASE_TABLE,
arg1,
arg2);
break;
case BOOK_ID:
String id = arg0.getPathSegments().get(1);
count = booksDB.delete(
DATABASE_TABLE,
_ID + " = " + id +
(!TextUtils.isEmpty(arg1) ? " AND (" +
arg1 + ')' : ""),
arg2);
break;
default: throw new IllegalArgumentException("Unknown URI " + arg0);
}
getContext().getContentResolver().notifyChange(arg0, null);
return count;
}
@Override
public String getType(Uri uri) {
switch (uriMatcher.match(uri)){
//---get all books---
case BOOKS:
return "vnd.android.cursor.dir/vnd.manoel.books ";
//---get a particular book---
case BOOK_ID:
return "vnd.android.cursor.item/vnd.manoel.books ";
default:
throw new IllegalArgumentException("Unsupported URI: " + uri);
}
}
@Override
public Uri insert(Uri uri, ContentValues values) {
//---add a new book---
long rowID = booksDB.insert(
DATABASE_TABLE,
"",
values);
//---if added successfully---
if (rowID>0)
{
Uri _uri = ContentUris.withAppendedId(CONTENT_URI, rowID);
getContext().getContentResolver().notifyChange(_uri, null);
return _uri;
}
throw new SQLException("Failed to insert row into " + uri);
}
@Override
public boolean onCreate() {
Context context = getContext();
DatabaseHelper dbHelper = new DatabaseHelper(context);
booksDB = dbHelper.getWritableDatabase();
return (booksDB == null)? false:true;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
SQLiteQueryBuilder sqlBuilder = new SQLiteQueryBuilder();
sqlBuilder.setTables(DATABASE_TABLE);
if (uriMatcher.match(uri) == BOOK_ID)
//---if getting a particular book---
sqlBuilder.appendWhere(
_ID + " = " + uri.getPathSegments().get(1));
if (sortOrder==null || sortOrder=="")
sortOrder = TITLE;
Cursor c = sqlBuilder.query(
booksDB,
projection,
selection,
selectionArgs,
null,
null,
sortOrder);
//---register to watch a content URI for changes---
c.setNotificationUri(getContext().getContentResolver(), uri);
return c;
}
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
int count = 0;
switch (uriMatcher.match(uri)){
case BOOKS:
count = booksDB.update(
DATABASE_TABLE,
values,
selection,
selectionArgs);
break;
case BOOK_ID:
count = booksDB.update(
DATABASE_TABLE,
values,
_ID + " = " + uri.getPathSegments().get(1) +
(!TextUtils.isEmpty(selection) ? " AND (" +
selection + ')' : ""),
selectionArgs);
break;
default: throw new IllegalArgumentException("Unknown URI " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return count;
}
}
4. 在AndroidManifest.xml中添加声明。
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="net.manoel.ContentProviders"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="14" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<activity
android:label="@string/app_name"
android:name=".ContentProvidersActivity" >
<intent-filter >
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<provider android:name="BooksProvider"
android:authorities="net.manoel.provider.Books">
</provider>
</application>
</manifest>
在这个例子中,首先创建一个ContentProvider的子类,名字叫BooksProvider。需要重写一些方法:
- getTpye() - 返回给定的URI数据的MIME类型
- onCreate() - 当provider启动的时候被调用
- query() - 接收客户的请求。返回一个Cursor对象。
- insert() - 向provider中插入一条新记录
- delete() - 在provider中删除一条已存在的记录
- update() - 在provider中更新一条已存在的记录
在content provider中,可以任意选择要存储的数据 - 传统的文件,XML,数据库,甚至web service。
接下来,在BooksProvider.java类中定义一些常量:
static final String PROVIDER_NAME =
"net.manoel.provider.Books";
static final Uri CONTENT_URI =
Uri.parse("content://"+ PROVIDER_NAME + "/books");
static final String _ID = "_id";
static final String TITLE = "title";
static final String ISBN = "isbn";
static final int BOOKS = 1;
static final int BOOK_ID = 2;
private static final UriMatcher uriMatcher;
static{
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(PROVIDER_NAME, "books", BOOKS);
uriMatcher.addURI(PROVIDER_NAME, "books/#", BOOK_ID);
}
观察上面的代码,使用的一个UriMatcher对象去转换URI,这个URI将会作为一个参数传递给ContentResolver。举个例子,下面的URI代表了请求所有的图书:
content://net.manoel.provider.Books/books
下面的URI代表了请求指定_id 5为的图书:
content://net.manoel.provider.Books/books/5
content provider 使用一个SQlite数据库去存储图书。注意一点,这里使用SQLiteOpenHelper辅助类去操纵数据库:
private static class DatabaseHelper extends SQLiteOpenHelper
{
DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db)
{
db.execSQL(DATABASE_CREATE);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion,
int newVersion) {
Log.w("Content provider database",
"Upgrading database from version " +
oldVersion + " to " + newVersion +
", which will destroy all old data");
db.execSQL("DROP TABLE IF EXISTS titles");
onCreate(db);
}
}
接下来,重写getType()方法,唯一可以描述content provider的数据类型。使用UriMatcher对象,返回vnd.android.cursor.item/vnd.manoel.books代表单独的一本书,vnd.android.cursor.dir/vnd.android.cursor.item/vnd.manoel.bools 代表多本书:
@Override
public String getType(Uri uri) {
switch (uriMatcher.match(uri)){
//---get all books---
case BOOKS:
return "vnd.android.cursor.dir/vnd.manoel.books ";
//---get a particular book---
case BOOK_ID:
return "vnd.android.cursor.item/vnd.manoel.books ";
default:
throw new IllegalArgumentException("Unsupported URI: " + uri);
}
}
然后,重写onCreate()方法,当provider被开启的时候,和数据库建立建立链接:
@Override
public boolean onCreate() {
Context context = getContext();
DatabaseHelper dbHelper = new DatabaseHelper(context);
booksDB = dbHelper.getWritableDatabase();
return (booksDB == null)? false:true;
}
然后,重新query()方法:
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
SQLiteQueryBuilder sqlBuilder = new SQLiteQueryBuilder();
sqlBuilder.setTables(DATABASE_TABLE);
if (uriMatcher.match(uri) == BOOK_ID)
//---if getting a particular book---
sqlBuilder.appendWhere(
_ID + " = " + uri.getPathSegments().get(1));
if (sortOrder==null || sortOrder=="")
sortOrder = TITLE;
Cursor c = sqlBuilder.query(
booksDB,
projection,
selection,
selectionArgs,
null,
null,
sortOrder);
//---register to watch a content URI for changes---
c.setNotificationUri(getContext().getContentResolver(), uri);
return c;
}
查询的结果是一个Cursor对象。
然后,重写insert()方法:
@Override
public Uri insert(Uri uri, ContentValues values) {
//---add a new book---
long rowID = booksDB.insert(
DATABASE_TABLE,
"",
values);
//---if added successfully---
if (rowID>0)
{
Uri _uri = ContentUris.withAppendedId(CONTENT_URI, rowID);
getContext().getContentResolver().notifyChange(_uri, null);
return _uri;
}
throw new SQLException("Failed to insert row into " + uri);
}
一旦新的记录插入成功,调用ContentResolver的nofityChande()方法。这就通知观察者一个新的记录被更新了。
然后,重新delete()方法:
@Override
public int delete(Uri arg0, String arg1, String[] arg2) {
// arg0 = uri
// arg1 = selection
// arg2 = selectionArgs
int count=0;
switch (uriMatcher.match(arg0)){
case BOOKS:
count = booksDB.delete(
DATABASE_TABLE,
arg1,
arg2);
break;
case BOOK_ID:
String id = arg0.getPathSegments().get(1);
count = booksDB.delete(
DATABASE_TABLE,
_ID + " = " + id +
(!TextUtils.isEmpty(arg1) ? " AND (" +
arg1 + ')' : ""),
arg2);
break;
default: throw new IllegalArgumentException("Unknown URI " + arg0);
}
getContext().getContentResolver().notifyChange(arg0, null);
return count;
}
最后,重写update()方法:
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
int count = 0;
switch (uriMatcher.match(uri)){
case BOOKS:
count = booksDB.update(
DATABASE_TABLE,
values,
selection,
selectionArgs);
break;
case BOOK_ID:
count = booksDB.update(
DATABASE_TABLE,
values,
_ID + " = " + uri.getPathSegments().get(1) +
(!TextUtils.isEmpty(selection) ? " AND (" +
selection + ')' : ""),
selectionArgs);
break;
default: throw new IllegalArgumentException("Unknown URI " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return count;
}
最后的最后,别忘了在AndroidManifest.xml中声明这个ContentProvider。
分享到:
相关推荐
Android高级编程雪梨作业之自定义ContentProvider 将任务01生词本作业中生成的生词本数据库通过自定义ContentProvider的方式,共享给其他应用。 要求如下: (1) 使用自定义SQLiteOpenHelper来管理数据库; (2) 提交...
android 数据库 以及自定义ContentProvider demo
这是学习ContentProvider的第二个练习。 里面自定义ContentProvider类来与SQLite交互。 大致类容就是:通过ContentProvider,创建自己的.db,操作自己的.db. 代码里有详细的解释
NULL 博文链接:https://sunzone.iteye.com/blog/1884167
android 自定义 ContentProvider 以及 ContentResolver
自定义contentprovider 在其它应用中访问该应用暴露的数据。
NULL 博文链接:https://catkingwong.iteye.com/blog/1313740
自定义ContentProvider完成数据交互,文章:http://write.blog.csdn.net/postedit/43950781
android自定义ContentProvider,可以实现程序之间共享数据
Android 自定义ContentProvider简单实例 Android允许我们定义自己的的ContentProvider对象来共享数据,练练手,简单来实现一下。 要使用ContentProvider来操作数据,必须要有保存数据的场所。可以使用文件或SQLite...
ContentProvider自定义以及使用系统ContentProvider
主要介绍了Android开发教程之ContentProvider数据存储的相关资料,需要的朋友可以参考下
包含了常用的contentprovider操作,读取联系人,读取彩信,读取通话记录,自定义的contentprovider等。
资源包涵两个Demo,其中一个是自定义的ContentProvider,另一个demo是访问第一个demo的ContentProvider并且去读写第一个demo的数据库。
Android应用开发使用ContentProvider以及SQLite实现对数据库的相关操作,可以直接操作数据库,也可以使用ContentProvider来对数据库进行间接操作。
在android中自定义一个ContentProvider大致需要四步:1,定义数据的MetaData;2,定义一个类继承ContentProvider;3,覆写自定义类中的getType(),onCreate(),insert(),delete(),update(),query()六个方法;4,在...
Android 中自定义ContentProvider与ContentObserver的使用简单实例 示例说明: 该示例中一共包含两个工程。其中一个工程完成了自定义ContentProvider,另外一个工程用于测试该自定义ContentProvider且在该工程中使用...
1、Android Room操作SQLite数据 2、ContentProvider使用,使用Room进行数据库操作