在Android平台上,ContentProvider是一种非常有用的组件,用于共享数据和简化数据访问的过程。ContentProvider能够帮助应用程序之间共享数据,同时提供了一种标准化的接口来访问数据。
一、ContentProvider的基本概念
ContentProvider是Android中的四大组件之一,其它三种组件是Activity、Service和BroadcastReceiver。ContentProvider的主要作用是提供数据给其他应用程序或其他部分的应用程序。ContentProvider是一个标准的接口,它用于访问数据。它隐藏了底层的数据访问方式,提供了一组标准的方法来进行数据访问。通过这些方法,应用程序可以添加、查询、更新和删除数据。
ContentProvider通过URI来标识和访问数据。URI包含三部分:schema、authority和path。例如,下面的URI表示一个ContentProvider,可以通过该ContentProvider来访问联系人数据。
content://com.android.contacts/contacts
URI的三部分:
- schema:URI的协议部分,表明这是一个ContentProvider的URI。
- authority:ContentProvider的唯一标识符。
- path:ContentProvider中数据的路径。
二、创建自定义ContentProvider
下面是一个简单的ContentProvider的创建过程,以提供联系人数据为例。
1.定义Provider的metadata
在AndroidManifest.xml文件中定义Provider的metadata:
<provider
android:name=".ContactsProvider"
android:authorities="com.example.provider.contacts"
android:exported="true" />
android:name:Provider的类名。
android:authorities:Provider的唯一标识符。
android:exported:是否允许其它应用程序访问Provider。
2.定义Provider的接口
创建一个类实现ContentProvider的接口:
public class ContactsProvider extends ContentProvider {
public static final String AUTHORITY = "com.example.provider.contacts";
private static final String DATABASE_NAME = "contacts.db";
private static final int DATABASE_VERSION = 1;
private static final String TABLE_NAME = "contacts";
private SQLiteDatabase database;
// onCreate方法:初始化数据库和表
public boolean onCreate() {
DatabaseHelper databaseHelper = new DatabaseHelper(getContext());
database = databaseHelper.getWritableDatabase();
return (database == null) ? false : true;
}
// getType方法:返回MIME类型
public String getType(Uri uri) {
return null;
}
// insert方法:插入一行数据
public Uri insert(Uri uri, ContentValues values) {
database.insert(TABLE_NAME, null, values);
getContext().getContentResolver().notifyChange(uri, null);
return uri;
}
// query方法:查询数据
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
// 根据查询参数获取需要查询的数据
Cursor cursor = database.query(TABLE_NAME,
new String[] { "id", "name", "phone" }, selection, selectionArgs, null, null, sortOrder);
cursor.setNotificationUri(getContext().getContentResolver(), uri);
return cursor;
}
// update方法:更新数据
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
int count = database.update(TABLE_NAME, values, selection, selectionArgs);
getContext().getContentResolver().notifyChange(uri, null);
return count;
}
// delete方法:删除数据
public int delete(Uri uri, String selection, String[] selectionArgs) {
int count = database.delete(TABLE_NAME, selection, selectionArgs);
getContext().getContentResolver().notifyChange(uri, null);
return count;
}
// DatabaseHelper类:用于创建和更新数据库
private static class DatabaseHelper extends SQLiteOpenHelper {
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
// onCreate方法:创建表
public void onCreate(SQLiteDatabase database) {
database.execSQL("CREATE TABLE IF NOT EXISTS " + TABLE_NAME +
"(id INTEGER PRIMARY KEY autoincrement, name TEXT, phone TEXT);");
}
// onUpgrade方法
public void onUpgrade(SQLiteDatabase database, int oldVersion, int newVersion) {
database.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
onCreate(database);
}
}
}
在上面的代码中,需要注意一下方法:
- onCreate:初始化ContentProvider的实例。
- getType:返回MIME类型。
- insert:插入一行数据。
- query:查询数据。
- update:更新数据。
- delete:删除数据。
3.使用自定义Provider
使用ContentProvider的步骤如下:
// 定义需要查询的数据
String[] projection = new String[] { "id", "name", "phone" };
String selection = "id = ?";
String[] selectionArgs = new String[] { "1" };
String sortOrder = "name desc";
// ContentResolver:用于访问ContentProvider
ContentResolver contentResolver = getContentResolver();
// 获取ContentProvider的数据,使用Cursor保存查询结果
Uri uri = Uri.parse("content://com.example.provider.contacts/contacts");
Cursor cursor = contentResolver.query(uri, projection, selection, selectionArgs, sortOrder);
// 遍历查询结果
while (cursor.moveToNext()) {
int id = cursor.getInt(cursor.getColumnIndex("id"));
String name = cursor.getString(cursor.getColumnIndex("name"));
String phone = cursor.getString(cursor.getColumnIndex("phone"));
Log.i(TAG, String.format("id=%s, name=%s, phone=%s", id, name, phone));
}
// 关闭Cursor
cursor.close();
在上面的代码中,需要注意一下几点:
- URI:ContentProvider的标识符。
- ContentResolver:用于访问ContentProvider。
- Cursor:用于保存查询结果。
三、ContentProvider的权限控制
ContentProvider能够控制访问权限,以允许或拒绝访问者访问数据。通过使用AndroidManifest.xml中的标签,可以控制ContentProvider的访问权限。
<provider
android:name=".ContactsProvider"
android:authorities="com.example.provider.contacts"
android:exported="false"
android:readPermission="com.example.provider.permission.READ_CONTACTS"
android:writePermission="com.example.provider.permission.WRITE_CONTACTS" />
android:readPermission和android:writePermission:用于控制读写权限。
当ContentProvider中有多个表或多种数据类型时,可以将URI分为不同的路径。例如下面的代码是一个内容提供者,可以访问联系人和日历表:
<provider
android:name=".ContactsProvider"
android:authorities="com.example.provider"
android:exported="false">
<!-- 联系人表 -->
<path-permission
android:pathPrefix="/contacts"
android:readPermission="com.example.provider.permission.READ_CONTACTS"
android:writePermission="com.example.provider.permission.WRITE_CONTACTS" />
<!-- 日历表 -->
<path-permission
android:pathPrefix="/calendar"
android:readPermission="com.example.provider.permission.READ_CALENDAR"
android:writePermission="com.example.provider.permission.WRITE_CALENDAR" />
</provider>
使用ContentProvider需要注意以下几点:
- ContentProvider提供了一种标准的接口来访问数据。
- ContentProvider可以通过URI来标识和访问数据。
- ContentProvider可以控制访问权限,以允许或拒绝访问者访问数据。
完整的代码示例:
// 定义Provider的metadata
<provider
android:name=".ContactsProvider"
android:authorities="com.example.provider.contacts"
android:exported="true" />
// 创建一个类实现ContentProvider的接口
public class ContactsProvider extends ContentProvider {
public static final String AUTHORITY = "com.example.provider.contacts";
private static final String DATABASE_NAME = "contacts.db";
private static final int DATABASE_VERSION = 1;
private static final String TABLE_NAME = "contacts";
private SQLiteDatabase database;
// onCreate方法:初始化数据库和表
public boolean onCreate() {
DatabaseHelper databaseHelper = new DatabaseHelper(getContext());
database = databaseHelper.getWritableDatabase();
return (database == null) ? false : true;
}
// getType方法:返回MIME类型
public String getType(Uri uri) {
return null;
}
// insert方法:插入一行数据
public Uri insert(Uri uri, ContentValues values) {
database.insert(TABLE_NAME, null, values);
getContext().getContentResolver().notifyChange(uri, null);
return uri;
}
// query方法:查询数据
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
// 根据查询参数获取需要查询的数据
Cursor cursor = database.query(TABLE_NAME,
new String[] { "id", "name", "phone" }, selection, selectionArgs, null, null, sortOrder);
cursor.setNotificationUri(getContext().getContentResolver(), uri);
return cursor;
}
// update方法:更新数据
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
int count = database.update(TABLE_NAME, values, selection, selectionArgs);
getContext().getContentResolver().notifyChange(uri, null);
return count;
}
// delete方法:删除数据
public int delete(Uri uri, String selection, String[] selectionArgs) {
int count = database.delete(TABLE_NAME, selection, selectionArgs);
getContext().getContentResolver().notifyChange(uri, null);
return count;
}
// DatabaseHelper类:用于创建和更新数据库
private static class DatabaseHelper extends SQLiteOpenHelper {
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
// onCreate方法:创建表
public void onCreate(SQLiteDatabase database) {
database.execSQL("CREATE TABLE IF NOT EXISTS " + TABLE_NAME +
"(id INTEGER PRIMARY KEY autoincrement, name TEXT, phone TEXT);");
}
// onUpgrade方法
public void onUpgrade(SQLiteDatabase database, int oldVersion, int newVersion) {
database.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
onCreate(database);
}
}
}
// 使用自定义Provider
// 定义需要查询的数据
String[] projection = new String[] { "id", "name", "phone" };
String selection = "id = ?";
String[] selectionArgs = new String[] { "1" };
String sortOrder = "name desc";
// ContentResolver:用于访问ContentProvider
ContentResolver contentResolver = getContentResolver();
// 获取ContentProvider的数据,使用Cursor保存查询结果
Uri uri = Uri.parse("content://com.example.provider.contacts/contacts");
Cursor cursor = contentResolver.query(uri, projection, selection, selectionArgs, sortOrder);
// 遍历查询结果
while (cursor.moveToNext()) {
int id = cursor.getInt(cursor.getColumnIndex("id"));
String name = cursor.getString(cursor.getColumnIndex("name"));
String phone = cursor.getString(cursor.getColumnIndex("phone"));
Log.i(TAG, String.format("id=%s, name=%s, phone=%s", id, name, phone));
}
// 关闭Cursor
cursor.close();