在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;
- }
- }
- <?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>
- <!-- 注意使用exported = "true"可以在其他应用程序的Activity或者Service中使用 -->
- <provider
- android:exported="true"
- 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;
- }
然后,重写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;
- }
使用ContentResolve使用自定义ContentProvider
public class MainActivity extends Activity {
private static final String TAG = "BooksProviderTest";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
try {
testSave();
} catch (Throwable e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void testSave() throws Throwable{
ContentResolver contentResolver =this.getBaseContext().getContentResolver();
Uri insertUri = Uri.parse("content://net.manoel.provider.Books/books");
ContentValues values = new ContentValues();
values.put("title", "lm");
values.put("isbn", "1350000009");
Uri uri = contentResolver.insert(insertUri, values);
Log.i(TAG, uri.toString());
}
public void testUpdate() throws Throwable{
ContentResolver contentResolver = this.getBaseContext().getContentResolver();
Uri updateUri = Uri.parse("content://net.manoel.provider.Books/books1");
ContentValues values = new ContentValues();
values.put("title", "linjiqin");
contentResolver.update(updateUri, values, null, null);
}
public void testFind() throws Throwable{
ContentResolver contentResolver = this.getBaseContext().getContentResolver();
//Uri uri = Uri.parse("content://com.ljq.provider.personprovider/person");
Uri uri = Uri.parse("content://net.manoel.provider.Books/books");
Cursor cursor = contentResolver.query(uri, null, null, null, "id asc");
while(cursor.moveToNext()){
int personid = cursor.getInt(cursor.getColumnIndex("_id"));
String name = cursor.getString(cursor.getColumnIndex("title"));
String phone = cursor.getString(cursor.getColumnIndex("isbn"));
Log.i(TAG, "_id="+ personid + ",title="+ name+ ",isbn="+ phone);
}
cursor.close();
}
public void testDelete() throws Throwable{
ContentResolver contentResolver = this.getBaseContext().getContentResolver();
Uri uri = Uri.parse("content://net.manoel.provider.Books/books/1");
contentResolver.delete(uri, null, null);
}
}
运行结果,插入了数据
注意,如果想在其他应用程序的Activity或Service中使用自定义的ContentProvider,要在配置文件中加入 android:exported="true"