ContentProvider 属于Android应用程序的组件之一,作为应用程序之间唯一的共享数据的途径,ContentProvider 主要的功能就是存储并检索数据以及向其他应用程序提供访问数据的接口。
让自己的数据和其他应用程序共享有两种方式:创建自己的ContentProvier(即继承自ContentProvider的子类) 或者是将自己的数据添加到已有的ContentProvider中去,后者需要保证现有的ContentProvider和自己的数据类型相同且具有该 ContentProvider的写入权限。对于ContentProvider,最重要的就是数据模型(data model) 和 URI。
一、数据模型
ContentProvider 将其存储的数据以数据表的形式提供给访问者,在数据表中每一行为一条记录,每一列为具有特定类型和意义的数据。每一条数据记录都包括一个 "_ID" 数值字段,改字段唯一标识一条数据。二、URI——统一资源标识符
URI,每一个Content Provider 都对外提供一个能够唯一标识自己数据集(data set)的公开URI, 如果一个Content Provider管理多个数据集,其将会为每个数据集分配一个独立的URI。所有的Content Provider 的URI 都以"content://" 开头,其中"content:"是用来标识数据是由Content Provider管理的 schema。
1 2 3 4
1、ContentProvider的scheme已经由Android所规定, scheme为:content:// 一般不改变
2、主机名(或叫Authority)用于唯一标识这个ContentProvider,外部调用者可以根据这个标识来找到它;一般我们都是用ContentProvider的继承类完整类名。
3、路径(path)可以用来表示我们要操作的数据,如果要操作整张表,后面就不需要了。
4、users中的子表
把一个字符串转化成URI
Uri uri = Uri.parse("content://com.example.contentproviderdemo.FirstContentProvider/users/id");
因为Uri代表了要操作的数据,所以我们经常需要解析Uri,并从Uri中获取数据。Android系统提供了两个用于操作Uri的工具类,分别为UriMatcher和ContentUris
UriMatcher的使用
public static final UriMatcher uriMatcher;
public static final int INCOMING_USER_COLLECTION = 1;
public static final int INCOMING_USER_SINGLE = 2;
static {
//UriMatcher.NO_MATCH表示不匹配任何路径的返回码
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
//匹配content://com.example.contentproviderdemo.FirstContentProvider/users路径,返回匹配码为INCOMING_USER_COLLECTION
uriMatcher.addURI(ProviderMetaData.AUTHORIY, "users",
INCOMING_USER_COLLECTION);
//匹配content://com.example.contentproviderdemo.FirstContentProvider/users/#路径,返回匹配码为INCOMING_USER_SINGLE
uriMatcher.addURI(ProviderMetaData.AUTHORIY, "users/#", //#号为通配符
INCOMING_USER_SINGLE);
}
//根据传入的URI,返回该URI所表示的数据类型
@Override
public String getType(Uri uri) {
// TODO Auto-generated method stub
System.out.println("getType------------>" + uriMatcher.match(uri) + " uri = " + uri.toString());
switch(uriMatcher.match(uri)){
case INCOMING_USER_COLLECTION:
System.out.println("getType-------------->INCOMING_USER_COLLECTION");
return UserTableMetaData.CONTENT_TYPE;
case INCOMING_USER_SINGLE:
System.out.println("getType-------------->INCOMING_USER_SINGLE");
return UserTableMetaData.CONTENT_TYPE_ITEM;
default:
System.out.println("getType-------------->default");
throw new IllegalArgumentException("Unknown URI" + uri);
}
}
ContentUris 的使用
ContentUris类用于操作Uri路径后面的ID部分,它有两个比较实用的方法:
withAppendedId(uri, id)用于为路径加上ID部分:
Uri uri = Uri.parse("content://com.example.contentproviderdemo.FirstContentProvider/users")
Uri resultUri = ContentUris.withAppendedId(uri, 10);
生成后的Uri为:content://com.example.contentproviderdemo.FirstContentProvider/users/10
parseId(uri)方法用于从路径中获取ID部分
Uri uri = Uri.parse("content://com.example.contentproviderdemo.FirstContentProvider/users/10")
long personid = ContentUris.parseId(uri);//获取的结果为:10
下面创建一个类继承ContentProvider重写增、删、改、查方法
package com.example.contentproviderdemo;
import java.util.HashMap;
import com.example.contentproviderdemo.ProviderMetaData.UserTableMetaData;
import com.sqlite3.db.DatabaseHelper;
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.text.TextUtils;
public class FirstContentProvider extends ContentProvider {
public static final UriMatcher uriMatcher;
public static final int INCOMING_USER_COLLECTION = 1;
public static final int INCOMING_USER_SINGLE = 2;
private DatabaseHelper dh;
static {
//UriMatcher.NO_MATCH表示不匹配任何路径的返回码
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
//匹配content://com.example.contentproviderdemo.FirstContentProvider/users路径,返回匹配码为INCOMING_USER_COLLECTION
uriMatcher.addURI(ProviderMetaData.AUTHORIY, "users",
INCOMING_USER_COLLECTION);
//匹配content://com.example.contentproviderdemo.FirstContentProvider/users/#路径,返回匹配码为INCOMING_USER_SINGLE
uriMatcher.addURI(ProviderMetaData.AUTHORIY, "users/#", //#号为通配符
INCOMING_USER_SINGLE);
}
public static HashMap<String,String> userProjectionMap;
static
{
userProjectionMap = new HashMap<String,String>();
userProjectionMap.put(UserTableMetaData._ID, UserTableMetaData._ID);
userProjectionMap.put(UserTableMetaData.USER_NAME, UserTableMetaData.USER_NAME);
}
@Override
public int delete(Uri arg0, String arg1, String[] arg2) {
// TODO Auto-generated method stub
System.out.println("delete");
return 0;
}
//根据传入的URI,返回该URI所表示的数据类型
@Override
public String getType(Uri uri) {
// TODO Auto-generated method stub
System.out.println("getType------------>" + uriMatcher.match(uri) + " uri = " + uri.toString());
switch(uriMatcher.match(uri)){
case INCOMING_USER_COLLECTION:
System.out.println("getType-------------->INCOMING_USER_COLLECTION");
return UserTableMetaData.CONTENT_TYPE;
case INCOMING_USER_SINGLE:
System.out.println("getType-------------->INCOMING_USER_SINGLE");
return UserTableMetaData.CONTENT_TYPE_ITEM;
default:
System.out.println("getType-------------->default");
throw new IllegalArgumentException("Unknown URI" + uri);
}
}
/**
* 该函数的返回值是一个Uri,这个Uri表示的是刚刚使用这个函数所插入的数据
* content://mars.cp.FirstContentProvider/users/1
*/
@Override
public Uri insert(Uri uri, ContentValues values) {
System.out.println("insert");
SQLiteDatabase db = dh.getWritableDatabase();
long rowId = db.insert(UserTableMetaData.TABLE_NAME, null, values);
if(rowId > 0){
Uri insertedUserUri = ContentUris.withAppendedId(UserTableMetaData.CONTENT_URI, rowId);
//通知监听器,数据已经改变
getContext().getContentResolver().notifyChange(insertedUserUri, null);
return insertedUserUri;
}
throw new SQLException("Failed to insert row into" + uri);
}
//是一个回调方法,所以说在ContentProvider创建的时候执行
@Override
public boolean onCreate() {
//打开数据库
dh = new DatabaseHelper(getContext(),ProviderMetaData.DATABASE_NAME);
System.out.println("onCreate");
return true;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder) {
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
switch(uriMatcher.match(uri)){
case INCOMING_USER_COLLECTION:
qb.setTables(UserTableMetaData.TABLE_NAME);
qb.setProjectionMap(userProjectionMap);
System.out.println("----------------------INCOMING_USER_COLLECTION");
break;
case INCOMING_USER_SINGLE:
qb.setTables(UserTableMetaData.TABLE_NAME);
qb.setProjectionMap(userProjectionMap);
qb.appendWhere(UserTableMetaData._ID + "=" + uri.getPathSegments().get(1));
System.out.println("----------------------INCOMING_USER_SINGLE");
break;
default:
break;
}
System.out.println("----------------------query");
String orderBy;
if(TextUtils.isEmpty(sortOrder)){
orderBy = UserTableMetaData.DEFAULT_SORT_ORDER;
}
else{
orderBy = sortOrder;
}
//SQLiteDatabase db = dh.getWritableDatabase();
SQLiteDatabase db = dh.getReadableDatabase();
System.out.println("query------------------2");
Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, orderBy);
System.out.println("query------------------3");
c.setNotificationUri(getContext().getContentResolver(), uri);
System.out.println("query");
return c;
}
@Override
public int update(Uri arg0, ContentValues arg1, String arg2, String[] arg3) {
// TODO Auto-generated method stub
System.out.println("update");
return 0;
}
}
定义一个保存常量的类 ProviderMetaData.java
package com.example.contentproviderdemo;
import android.net.Uri;
import android.provider.BaseColumns;
/**
* 定义程序中用到的常量
* @author Administrator
*
*/
public class ProviderMetaData {
public static final String AUTHORIY = "com.example.contentproviderdemo.FirstContentProvider";
//数据库名称
public static final String DATABASE_NAME = "FirstProvider1.db";
//数据库的版本
public static final int DATABASE_VERSION = 2;
//表名
public static final String USERS_TABLE_NAME = "users";
public static final class UserTableMetaData implements BaseColumns{
//表名
public static final String TABLE_NAME = "users";
//访问该ContentProvider的URI
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORIY + "/users");
//该ContentProvider所返回的数据类型的定义
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.firstprovider.user";
public static final String CONTENT_TYPE_ITEM = "vnd.android.cursor.item/vnd.firstprovider.user";
//列名
public static final String USER_NAME = "name";
//默认的排序方法
public static final String DEFAULT_SORT_ORDER = "_id desc";
}
}
在Activity中定义两个按钮,进行插入和查询操作
package com.example.contentproviderdemo;
import com.example.contentproviderdemo.ProviderMetaData.UserTableMetaData;
import android.net.Uri;
import android.os.Bundle;
import android.app.Activity;
import android.content.ContentValues;
import android.database.Cursor;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class CPActivity extends Activity {
private Button insertButton = null;
private Button queryButton = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_cp);
queryButton = (Button) findViewById(R.id.query);
insertButton = (Button) findViewById(R.id.insert);
insertButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
ContentValues values = new ContentValues();
values.put(ProviderMetaData.UserTableMetaData.USER_NAME,
"zhangsan");
Uri uri = getContentResolver().insert(ProviderMetaData.UserTableMetaData.CONTENT_URI, values);
System.out.println("uri--->" + uri.toString());
}
});
queryButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
Cursor c = getContentResolver().query(
ProviderMetaData.UserTableMetaData.CONTENT_URI, null,
null, null, null);
while(c.moveToNext()){
System.out.println(c.getString(c.getColumnIndex(UserTableMetaData.USER_NAME)));
}
String str = getContentResolver().getType(ProviderMetaData.UserTableMetaData.CONTENT_URI);
System.out.println("queryButton--->" + str);
}
});
}
}
得到的结果是
样例代码