ContentProvider的定义
为存储和获取数据提供统一的接口。可以在不同的应用程序之间共享数据。
ContentProvider提供的方法
- query:查询
- insert:插入
- update:更新
- delete:删除
- getType:得到数据类型
- onCreate:创建数据时调用的回调函数
ContentProvider的特点
1)、ContentProvider为存储和获取数据提供了统一的接口。ContentProvide对数据进行封装,不用关心数据存储的细节。使用表的形式来组织数据。
2)、使用ContentProvider可以在不同的应用程序之间共享数据。
3)、Android为常见的一些数据提供了默认的ContentProvider(包括音频、视频、图片和通讯录等)。
Uri的介绍
用到ContentProvider 就不得不介绍一下Uri了 因为ContentProvider的对外提供的数据就是用URI形式体现的。
Uri代表了要操作的数据,Uri主要包含了两部分信息:
1、需要操作的ContentProvider ,
2、对ContentProvider中的什么数据进行操作,
例如:content://com.zhi.example.myprovider/tablename/id
一个Uri由以下几部分组成:
1. 标准前缀,用来说明一个Content Provider控制这些数据,无法改变的;”content://”
2. URI 的标识,用于唯一标识这个ContentProvider,外部调用者可以根据这个标识来找到它。它定义了是哪个ContentProvider提供这些数据。对于第三方应用程序,为了保证URI标识的唯一性,它必须是一个完整的、小写的类名。这个标识在元素的authorities属性中说明:一般是定义该ContentProvider的包.类的名称。 例如:com.zhi.contentprovider.mycontentprovider
3. 路径(path),通俗的讲就是你要操作的数据库中表的名字,或者你也可以自己定义,记得在使用的时候保持一致就可以了;”content://com.zhi.contentprovider.mycontentprovider/tablename”
4. 如果URI中包含表示需要获取的记录的ID;则就返回该id对应的数据,如果没有ID,就表示返回全部;
“content://com.zhi.contentprovider.mycontentprovider/tablename/#” #表示数据id。
另外:
路径(path)可以用来表示我们要操作的数据,路径的构建应根据业务而定,如下:
要操作person表中id为10的记录,可以构建这样的路径:/person/10
要操作person表中id为10的记录的name字段, person/10/name
要操作person表中的所有记录,可以构建这样的路径:/person
要操作xxx表中的记录,可以构建这样的路径:/xxx
当然要操作的数据不一定来自数据库,也可以是文件、xml或网络等其他存储方式,如下:
要操作xml文件中person节点下的name节点,可以构建这样的路径:/person/name
如果要把一个字符串转换成Uri,可以使用Uri类中的parse()方法,如下:
Uri uri = Uri.parse(“content://com.zhi.contentprovider.mycontentprovider/person”)
UriMatcher类
Uri代表了要操作的数据,所以我们需要解析Uri,并从Uri中获取数据。Android系统提供了两个用于操作Uri的工具类,分别为UriMatcher和ContentUris 。掌握它们的使用,会便于我们的开发工作。
UriMatcher类用于匹配Uri,它的用法如下:
1、 初始化
//常量UriMatcher.NO_MATCH表示不匹配任何路径的返回码
UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
2、 注册需要的Uri
matcher.addURI("com.zhi.mycontentprovider", "people", PEOPLE);
matcher.addURI("com.zhi.mycontentprovider", "person/#", PEOPLE_ID);
3、 对已经注册的Uri进行匹配:
Uri uri = Uri.parse("content://" + "com.zhi.mycontentprovider" + "/people");
//匹配,并得到返回码
int match = matcher.match(uri);
//对返回码进行分析,返回响应的Uri;
switch (match)
{
case PEOPLE:
return "vnd.android.cursor.dir/people";
case PEOPLE_ID:
return "vnd.android.cursor.item/people";
default:
return null;
}
ContentUris类
ContentUris类用于操作Uri路径后面的ID部分,它有两个比较实用的方法
1、public static Uri withAppendedId(Uri contentUri, long id)
这个方法负责把id和contentUri连接成一个新的Uri。
例如 contentUri为content://com.bing.provider.personprovider/person
id为10
那么使用这个方法返回的新的Uri的值为content://com.zhi.mycontentprovider/person/10
2、 public static long parseId(Uri contentUri)
这个方法负责把content URI 后边的id解析出来,比如现在这个content URI 是content://com.zhi.mycontentprovider/person/10,
那么这个函数的返回值就是10。
如何使用ContentProvider
1、自定义一个类,继承SQLiteOpenHelper,并实现数据库的创建
2、自定义一个类,继承ContentProvider ,实现数据的增删查更新等操作。
3、在Activity获取一个ContentResolver实例 ,用ContentResolver来管理ContentProvider,
4、在AndroidManifest.xml中注册自定义的ContentProvider 类
下面通过一个自己test的例子来说明一下:
实现一个类DatabaseHelper继承SQLiteOpenHelper
package com.zhi.contentprovider;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import com.zhi.contentprovider.Provider.PersonColumns;
/**
* SQL数据库的创建
* @author zhi
*
*/
public class DatabaseHelper extends SQLiteOpenHelper {
//数据库的名称
private final static String DATABASE_NAME="dbZhi.db";
//数据库的版本号
private final static int DATABASE_VERSION =1;
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
// TODO Auto-generated constructor stub
}
@Override
public void onCreate(SQLiteDatabase db) {
// TODO Auto-generated method stub
//创建一个Person的表
db.execSQL("CREATE TABLE " + PersonColumns.TABLE_NAME + " ("
+ PersonColumns._ID + " INTEGER PRIMARY KEY,"
+ PersonColumns.NAME + " TEXT,"
+ PersonColumns.AGE + " INTEGER"
+ ");");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// TODO Auto-generated method stub
//当有数据库更新时,删掉这个表,并重新创建(注意,在实际编程中,存在表中的数据一般都是重要的,不能这删除表,应该在现有表的基础上增加字段等操作)
db.execSQL("DROP TABLE IF EXISTS " + PersonColumns.TABLE_NAME);
onCreate(db);
}
}
实现一个类PersionProvide继承ContentProvider
package com.zhi.contentprovider;
import java.util.HashMap;
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.net.Uri;
import android.text.TextUtils;
/**
* 内容提供者组件
* @author zhi
*
*/
public class PersionProvide extends ContentProvider {
//声明一个集合变量
private static HashMap<String, String> sPersonsProjectionMap;
//创建代号
private static final int PERSONS = 1;
private static final int PERSONS_ID = 2;
private static final UriMatcher sUriMatcher;
private DatabaseHelper mOpenHelper;
@Override
public boolean onCreate() {
// TODO Auto-generated method stub
//初始化一个DatabaseHelper实例
mOpenHelper=new DatabaseHelper(getContext());
return true;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
// TODO Auto-generated method stub
//查询操作
return null;
}
@Override
public String getType(Uri uri) {
// TODO Auto-generated method stub
//返回数据类型
switch (sUriMatcher.match(uri)) {
case PERSONS:
return Provider.CONTENT_TYPE;
case PERSONS_ID:
return Provider.CONTENT_ITEM_TYPE;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
}
@Override
public Uri insert(Uri uri, ContentValues values) {
// TODO Auto-generated method stub
//插入数据
if (sUriMatcher.match(uri) != PERSONS) {
throw new IllegalArgumentException("Unknown URI " + uri);
}
ContentValues values2 = null;
if (null!=values) {
values2=new ContentValues(values);
}else {
values=new ContentValues();
}
// Make sure that the fields are all set
if (values2.containsKey(Provider.PersonColumns.NAME) == false) {
values2.put(Provider.PersonColumns.NAME, "");
}
if (values2.containsKey(Provider.PersonColumns.AGE) == false) {
values2.put(Provider.PersonColumns.AGE, 0);
}
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
long rowId = db.insert(Provider.PersonColumns.TABLE_NAME, Provider.PersonColumns.NAME, values2);
if (rowId > 0) {
Uri noteUri = ContentUris.withAppendedId(Provider.PersonColumns.CONTENT_URI, rowId);
getContext().getContentResolver().notifyChange(noteUri, null);
return noteUri;
}
throw new SQLException("Failed to insert row into " + uri);
}
@Override
public int delete(Uri uri, String where, String[] whereArgs) {
// TODO Auto-generated method stub
//删除数据
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
int count;
switch (sUriMatcher.match(uri)) {
case PERSONS:
count = db.delete(Provider.PersonColumns.TABLE_NAME, where, whereArgs);
break;
case PERSONS_ID:
String noteId = uri.getPathSegments().get(1);
count = db.delete(Provider.PersonColumns.TABLE_NAME, Provider.PersonColumns._ID + "=" + noteId
+ (!TextUtils.isEmpty(where) ? " AND (" + where + ')' : ""), whereArgs);
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return count;
}
@Override
public int update(Uri uri, ContentValues values, String where,
String[] whereArgs) {
// TODO Auto-generated method stub
//更新数据
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
int count;
switch (sUriMatcher.match(uri)) {
case PERSONS:
count = db.update(Provider.PersonColumns.TABLE_NAME, values, where, whereArgs);
break;
case PERSONS_ID:
String noteId = uri.getPathSegments().get(1);
count = db.update(Provider.PersonColumns.TABLE_NAME, values, Provider.PersonColumns._ID + "=" + noteId
+ (!TextUtils.isEmpty(where) ? " AND (" + where + ')' : ""), whereArgs);
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return count;
}
static {
sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
// 这个地方的persons要和PersonColumns.CONTENT_URI中最后面的一个Segment一致
sUriMatcher.addURI(Provider.AUTHORITY, "persons", PERSONS);
sUriMatcher.addURI(Provider.AUTHORITY, "persons/#", PERSONS_ID);
sPersonsProjectionMap = new HashMap<String, String>();
sPersonsProjectionMap.put(Provider.PersonColumns._ID, Provider.PersonColumns._ID);
sPersonsProjectionMap.put(Provider.PersonColumns.NAME, Provider.PersonColumns.NAME);
sPersonsProjectionMap.put(Provider.PersonColumns.AGE, Provider.PersonColumns.AGE);
}
}