您的位置:首页 > 移动开发 > Android开发

【Android基础知识】ContentProvider(二)自定义ContentProvider和URI

2016-06-06 11:45 597 查看
在Android平台上创建ContentProvider,相对而言是很容易的。你所需做的就是继承ContentProvider这个抽象类,然后重新它里面的各种方法。

下面将介绍如何创建一个ContentProvider,用来存储一些图书的信息。



1. 使用Eclipse创建一个工程,ContentProviders。

2. 新建一个名为BooksProvider类。

3. BooksProvider.Java中的代码。

[java] view
plain copy







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中添加声明。

[html] view
plain copy







<?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类中定义一些常量:

[java] view
plain copy







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辅助类去操纵数据库:

[java] view
plain copy







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 代表多本书:

[java] view
plain copy







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

[java] view
plain copy







@Override

public boolean onCreate() {

Context context = getContext();

DatabaseHelper dbHelper = new DatabaseHelper(context);

booksDB = dbHelper.getWritableDatabase();

return (booksDB == null)? false:true;

}

然后,重新query()方法:

[java] view
plain copy







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

[java] view
plain copy







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

[java] view
plain copy







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

[java] view
plain copy







@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"

文章转自: http://blog.csdn.net/manoel/article/details/10578587
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息