Content Provider 屬于Android應用程式的元件之一,作為應用程式之間唯一的共享資料的途徑,Content Provider 主要的功能就是存儲并檢索資料以及向其他應用程式提供通路資料的借口。
Android 系統為一些常見的資料類型(如音樂、視訊、圖像、手機通信錄聯系人資訊等)内置了一系列的 Content Provider, 這些都位于android.provider包下。持有特定的許可,可以在自己開發的應用程式中通路這些Content Provider。
讓自己的資料和其他應用程式共享有兩種方式:建立自己的Content Provier(即繼承自ContentProvider的子類) 或者是将自己的資料添加到已有的Content Provider中去,後者需要保證現有的Content Provider和自己的資料類型相同且具有該 Content Provider的寫入權限。對于Content Provider,最重要的就是資料模型(data model) 和 URI。
1.資料模型
Content Provider 将其存儲的資料以資料表的形式提供給通路者,在資料表中每一行為一條記錄,每一列為具有特定類型和意義的資料。每一條資料記錄都包括一個 "_ID" 數值字段,改字段唯一辨別一條資料。
2.URI
URI,每一個Content Provider 都對外提供一個能夠唯一辨別自己資料集(data set)的公開URI, 如果一個Content Provider管理多個資料集,其将會為每個資料集配置設定一個獨立的URI。所有的Content Provider 的URI 都以"content://" 開頭,其中"content:"是用來辨別資料是由Content Provider管理的 schema。
在幾乎所有的Content Provider 的操作中都會用到URI,是以一般來講,如果是自己開發的Content Provider,最好将URI定義為常量,這樣在簡化開發的同時也提高了代碼的可維護性。
首先來介紹如何通路Content Provider中的資料,通路 Content Provider中的資料主要通過ContentResolver對象,ContentResolver類提供了成員方法可以用來對Content Provider 中的資料進行查詢、插入、修改和删除等操作。 以查詢為例,查詢一個 Content Provider 需要掌握如下的資訊。
唯一辨別Content Provider 的URI
需要通路的資料字段名稱。
該資料字段的資料類型
提示: 如果需要通路特定的某條資料記錄,隻需該記錄的ID 即可。
查詢Content Provider的方法有兩個:ContentResolver的query() 和 Activity 對象的 managedQuery(),二者接收的參數均相同,傳回的都是Cursor 對象,唯一不同的是 使用managedQuery 方法可以讓Activity 來管理 Cursor 的生命周期。
被管理的Cursor 會在 Activity進入暫停狀态的時候調用自己的 deactivate 方法自行解除安裝,而在Activity回到運作狀态時會調用自己的requery 方法重新查詢生成的Cursor對象。如果一個未被管理的Cursor對象想被Activity管理,可以調用Activity的 startManagingCursor方法來實作。
Android應用程式可以使用檔案或SqlLite資料庫來存儲資料。Content Provider提供了一種多應用間資料共享的方式,比如:聯系人資訊可以被多個應用程式通路。Content Provider是個實作了一組用于提供其他應用程式存取資料的标準方法的類。
應用程式可以在Content Provider中執行如下操作:
查詢資料
修改資料
添加資料
删除資料
/Chapter10_ContentProvider_01_Test02/src/com/amaker/ch10/app/MainActivity.java
代碼
package com.amaker.ch10.app;
import android.app.Activity;
import android.content.ContentUris;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import com.amaker.ch10.app.Employees.Employee;
public class MainActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// 添加
insert();
// 查詢
query();
// 更新
update();
// 删除
del();
}
// 删除方法
private void del(){
// 删除ID為1的記錄
Uri uri = ContentUris.withAppendedId(Employee.CONTENT_URI, 1);
// 獲得ContentResolver,并删除
getContentResolver().delete(uri, null, null);
// 更新
private void update(){
// 更新ID為1的記錄
ContentValues values = new ContentValues();
// 添加員工資訊
values.put(Employee.NAME, "hz.guo");
values.put(Employee.GENDER, "male");
values.put(Employee.AGE,31);
// 獲得ContentResolver,并更新
getContentResolver().update(uri, values, null, null);
// 查詢
private void query(){
// 查詢列數組
String[] PROJECTION = new String[] {
Employee._ID, // 0
Employee.NAME, // 1
Employee.GENDER, // 2
Employee.AGE // 3
};
// 查詢所有備忘錄資訊
Cursor c = managedQuery(Employee.CONTENT_URI, PROJECTION, null,
null, Employee.DEFAULT_SORT_ORDER);
// 判斷遊标是否為空
if (c.moveToFirst()) {
// 周遊遊标
for (int i = 0; i < c.getCount(); i++) {
c.moveToPosition(i);
// 獲得姓名
String name = c.getString(1);
String gender = c.getString(2);
int age = c.getInt(3);
// 輸出日志
Log.i("emp", name+":"+gender+":"+age);
}
}
// 插入
private void insert(){
// 聲明Uri
Uri uri = Employee.CONTENT_URI;
// 執行個體化ContentValues
values.put(Employee.NAME, "amaker");
values.put(Employee.AGE,30);
// 獲得ContentResolver,并插入
getContentResolver().insert(uri, values);
}
/Chapter10_ContentProvider_01_Test02/src/com/amaker/ch10/app/Employees.java
import android.provider.BaseColumns;
/**
* 通訊錄常量類
*/
public final class Employees {
// 授權常量
public static final String AUTHORITY = "com.amaker.provider.Employees";
private Employees() {}
// 内部類
public static final class Employee implements BaseColumns {
// 構造方法
private Employee() {}
// 通路Uri
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/employee");
// 内容類型
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.amaker.employees";
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.amaker.employees";
// 預設排序常量
public static final String DEFAULT_SORT_ORDER = "name DESC";// 按姓名排序
// 表字段常量
public static final String NAME = "name"; // 姓名
public static final String GENDER= "gender"; // 性别
public static final String AGE = "age"; // 年齡
/Chapter10_ContentProvider_01_Test02/src/com/amaker/ch10/app/EmployeeProvider.java
import java.util.HashMap;
import android.content.ContentProvider;
import android.content.UriMatcher;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;
import android.text.TextUtils;
public class EmployeeProvider extends ContentProvider{
// 資料庫幫助類
private DBHelper dbHelper;
// Uri工具類
private static final UriMatcher sUriMatcher;
// 查詢、更新條件
private static final int EMPLOYEE = 1;
private static final int EMPLOYEE_ID = 2;
// 查詢列集合
private static HashMap<String, String> empProjectionMap;
static {
// Uri比對工具類
sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
sUriMatcher.addURI(Employees.AUTHORITY, "employee", EMPLOYEE);
sUriMatcher.addURI(Employees.AUTHORITY, "employee/#", EMPLOYEE_ID);
// 執行個體化查詢列集合
empProjectionMap = new HashMap<String, String>();
// 添加查詢列
empProjectionMap.put(Employee._ID, Employee._ID);
empProjectionMap.put(Employee.NAME, Employee.NAME);
empProjectionMap.put(Employee.GENDER, Employee.GENDER);
empProjectionMap.put(Employee.AGE, Employee.AGE);
// 建立是調用
public boolean onCreate() {
// 執行個體化資料庫幫助類
dbHelper = new DBHelper(getContext());
return true;
// 添加方法
public Uri insert(Uri uri, ContentValues values) {
// 獲得資料庫執行個體
SQLiteDatabase db = dbHelper.getWritableDatabase();
// 插入資料,傳回行ID
long rowId = db.insert(DBHelper.EMPLOYEES_TABLE_NAME, Employee.NAME, values);
// 如果插入成功傳回uri
if (rowId > 0) {
Uri empUri = ContentUris.withAppendedId(Employee.CONTENT_URI, rowId);
getContext().getContentResolver().notifyChange(empUri, null);
return empUri;
return null;
public int delete(Uri uri, String selection, String[] selectionArgs) {
// 獲得資料庫執行個體
int count;
switch (sUriMatcher.match(uri)) {
// 根據指定條件删除
case EMPLOYEE:
count = db.delete(DBHelper.EMPLOYEES_TABLE_NAME, selection, selectionArgs);
break;
// 根據指定條件和ID删除
case EMPLOYEE_ID:
String noteId = uri.getPathSegments().get(1);
count = db.delete(DBHelper.EMPLOYEES_TABLE_NAME, Employee._ID + "=" + noteId
+ (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : ""), selectionArgs);
default:
throw new IllegalArgumentException("錯誤的 URI " + uri);
getContext().getContentResolver().notifyChange(uri, null);
return count;
// 獲得類型
public String getType(Uri uri) {
// 查詢方法
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
switch (sUriMatcher.match(uri)) {
// 查詢所有
case EMPLOYEE:
qb.setTables(DBHelper.EMPLOYEES_TABLE_NAME);
qb.setProjectionMap(empProjectionMap);
break;
// 根據ID查詢
case EMPLOYEE_ID:
qb.appendWhere(Employee._ID + "=" + uri.getPathSegments().get(1));
default:
throw new IllegalArgumentException("Uri錯誤! " + uri);
// 使用預設排序
String orderBy;
if (TextUtils.isEmpty(sortOrder)) {
orderBy = Employee.DEFAULT_SORT_ORDER;
} else {
orderBy = sortOrder;
// 獲得資料庫執行個體
SQLiteDatabase db = dbHelper.getReadableDatabase();
// 傳回遊标集合
Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, orderBy);
c.setNotificationUri(getContext().getContentResolver(), uri);
return c;
// 更新方法
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
// 根據指定條件更新
count = db.update(DBHelper.EMPLOYEES_TABLE_NAME, values, selection, selectionArgs);
// 根據指定條件和ID更新
count = db.update(DBHelper.EMPLOYEES_TABLE_NAME, values, Employee._ID + "=" + noteId
/Chapter10_ContentProvider_01_Test02/src/com/amaker/ch10/app/DBHelper.java
import android.content.Context;
import android.database.sqlite.SQLiteOpenHelper;
*
* 資料庫工具類
public class DBHelper extends SQLiteOpenHelper{
// 資料庫名稱常量
private static final String DATABASE_NAME = "Employees.db";
// 資料庫版本常量
private static final int DATABASE_VERSION = 1;
// 表名稱常量
public static final String EMPLOYEES_TABLE_NAME = "employee";
// 構造方法
public DBHelper(Context context) {
// 建立資料庫
super(context, DATABASE_NAME,null, DATABASE_VERSION);
// 建立時調用
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE " + EMPLOYEES_TABLE_NAME + " ("
+ Employee._ID + " INTEGER PRIMARY KEY,"
+ Employee.NAME + " TEXT,"
+ Employee.GENDER + " TEXT,"
+ Employee.AGE + " INTEGER"
+ ");");
// 版本更新時調用
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// 删除表
db.execSQL("DROP TABLE IF EXISTS employee");
onCreate(db);
/Chapter10_ContentProvider_01_Test02/AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.amaker.ch10.app"
android:versionCode="1"
android:versionName="1.0">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<provider android:name="EmployeeProvider"
android:authorities="com.amaker.provider.Employees"/>
<activity android:name=".MainActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
<uses-sdk android:minSdkVersion="3" />
</manifest>
本文轉自linzheng 51CTO部落格,原文連結:http://blog.51cto.com/linzheng/1079362