本章节翻译自《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);}@Overridepublic void onCreate(SQLiteDatabase db){db.execSQL(DATABASE_CREATE);}@Overridepublic 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);}}@Overridepublic int delete(Uri arg0, String arg1, String[] arg2) {// arg0 = uri // arg1 = selection// arg2 = selectionArgsint 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;}@Overridepublic 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);}}@Overridepublic 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);}@Overridepublic boolean onCreate() {Context context = getContext();DatabaseHelper dbHelper = new DatabaseHelper(context);booksDB = dbHelper.getWritableDatabase();return (booksDB == null)? false:true;}@Overridepublic 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;}@Overridepublic 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);}@Overridepublic void onCreate(SQLiteDatabase db){db.execSQL(DATABASE_CREATE);}@Overridepublic 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 代表多本书:

@Overridepublic 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被开启的时候,和数据库建立建立链接:

@Overridepublic boolean onCreate() {Context context = getContext();DatabaseHelper dbHelper = new DatabaseHelper(context);booksDB = dbHelper.getWritableDatabase();return (booksDB == null)? false:true;}

然后,重新query()方法:

@Overridepublic 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()方法:

@Overridepublic 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()方法:

@Overridepublic int delete(Uri arg0, String arg1, String[] arg2) {// arg0 = uri // arg1 = selection// arg2 = selectionArgsint 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()方法:

@Overridepublic 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。

更多相关文章

  1. Android(安卓)简单音乐播放器开发
  2. android应用:startActivityForResult使用实例
  3. android xml解析 XmlPullParser的使用
  4. Android(安卓)实现长按弹出PopupMenu 菜单栏
  5. Android(安卓)Handler机制6--消息的取出及分发
  6. 13-6-3 android 自定义tabhost在底部与框架函数的讲解2
  7. Android(安卓)native 内存泄露检测
  8. Android(安卓)-- Context
  9. Android遇到的问题解决方法

随机推荐

  1. 2014-11-8Android学习------Android(安卓
  2. JNI之------NDK开发环境的配置
  3. [原创] android学习和广告平台赚钱
  4. Android中的控件
  5. 谷歌发布 Android(安卓)2.2:运行速度提高2
  6. Android的Socket通信编程实例
  7. Android事件分发机制完全解析,带你从源码
  8. Android的事件简介
  9. Android(安卓)UI【android 仿微信、QQ聊
  10. Android中View和ViewGroup介绍