当应用继承ContentProvider类,并重写该类用于提供数据和存储数据的方法,就可以向其他应用共享其数据。以前我们学习过文件的操作模式,通过指定文件的操作模式为Context.MODE_WORLD_READABLE 或Context.MODE_WORLD_WRITEABLE同样可以对外共享数据,但数据的访问方式会因数据存储的方式而不同,如:采用xml文件对外共享数据,需要进行xml解析来读写数据;采用sharedpreferences共享数据,需要使用sharedpreferences API读写数据。而使用ContentProvider共享数据的好处是统一了数据访问方式。
当应用需要通过ContentProvider对外共享数据时,第一步需要继承ContentProvider并重写下面方法:
public class PersonContentProvider extends ContentProvider{
public boolean onCreate()
public Uri insert(Uri uri, ContentValues values)
public int delete(Uri uri, String selection, String[] selectionArgs)
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
public String getType(Uri uri)}
第二步需要在AndroidManifest.xml使用
了authorities(主机名/域名)对它进行唯一标识,你可以把ContentProvider看作是一个网站(想想,网站也是提供数据者),authorities就是他的域名:
注意:一旦应用继承了ContentProvider类,后面我们就会把这个应用称为ContentProvider(内容提供者)。
Uri代表了要操作的数据,Uri主要包含了两部分信息:1》需要操作的ContentProvider ,2》对ContentProvider中的什么数据进行操作,一个Uri由以下几部分组成:
ContentProvider(内容提供者)的scheme已经由Android所规定,scheme为:content://
主机名(或叫Authority)用于唯一标识这个ContentProvider,外部调用者可以根据这个标识来找到它。
路径(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://cn.itcast.provider.personprovider/person")因为Uri代表了要操作的数据,所以我们经常需要解析Uri,并从Uri中获取数据。Android系统提供了两个用于操作Uri的工具类,分别为UriMatcher和ContentUris。
掌握它们的使用,会便于我们的开发工作。
UriMatcher类用于匹配Uri,它的用法如下:
首先第一步把你需要匹配Uri路径全部给注册上,如下:
//常量UriMatcher.NO_MATCH表示不匹配任何路径的返回码
UriMatcher sMatcher = new UriMatcher(UriMatcher.NO_MATCH);
//如果match()方法匹配content://cn.itcast.provider.personprovider/person路径,返回匹配码为1
sMatcher.addURI(“cn.itcast.provider.personprovider”, “person”, 1);//添加需要匹配uri,如果匹配就会返回匹配码
//如果match()方法匹配content://cn.itcast.provider.personprovider/person/230路径,返回匹配码为2
sMatcher.addURI(“cn.itcast.provider.personprovider”, “person/#”, 2);//#号为通配符
switch (sMatcher.match(Uri.parse("content://cn.itcast.provider.personprovider/person/10"))) {
case 1
break;
case 2
break;
default://不匹配
break;
}
注册完需要匹配的Uri后,就可以使用sMatcher.match(uri)方法对输入的Uri进行匹配,如果匹配就返回匹配码,匹配码是调用addURI()方法传入的第三个参数,假
设匹配content://cn.itcast.provider.personprovider/person路径,返回的匹配码为1
ContentUris类用于获取Uri路径后面的ID部分,它有两个比较实用的方法:
withAppendedId(uri, id)用于为路径加上ID部分:
Uri uri =Uri.parse("content://cn.itcast.provider.personprovider/person")
Uri resultUri =ContentUris.withAppendedId(uri, 10);
//生成后的Uri为:content://cn.itcast.provider.personprovider/person/10
parseId(uri)方法用于从路径中获取ID部分:
Uri uri =Uri.parse("content://cn.itcast.provider.personprovider/person/10")
long personid =ContentUris.parseId(uri);//获取的结果为:10
ContentProvider类主要方法的作用:
public boolean onCreate()
该方法在ContentProvider创建后就会被调用, Android开机后, ContentProvider在其它应用第一次访问它时才会被创建。
public Uriinsert(Uri uri, ContentValues values)
该方法用于供外部应用往ContentProvider添加数据。
public int delete(Uri uri, String selection,String[] selectionArgs)
该方法用于供外部应用从ContentProvider删除数据。
public int update(Uri uri, ContentValues values, Stringselection, String[] selectionArgs)
该方法用于供外部应用更新ContentProvider中的数据。
public Cursorquery(Uri uri, String[]projection, String selection, String[] selectionArgs, String sortOrder)
该方法用于供外部应用从ContentProvider中获取数据。
public String getType(Uri uri)
该方法用于返回当前Url所代表数据的MIME类型。如果操作的数据属于集合类型,那么MIME类型字符串应该以vnd.android.cursor.dir/开头,例如:要得到所有person记录的Uri为content://cn.itcast.provider.personprovider/person,那么返回的MIME类型字符串应该为:“vnd.android.cursor.dir/person”。如果要操作的数据属于非集合类型数据,那么MIME类型字符串应该以vnd.android.cursor.item/开头,例如:得到id为10的person记录,Uri为content://cn.itcast.provider.personprovider/person/10,那么返回的MIME类型字符串应该为:“vnd.android.cursor.item/person”。
使用ContentResolver操作ContentProvider中的数据当外部应用需要对ContentProvider中的数据进行添加、删除、修改和查询操作时,可以使用ContentResolver 类来完成,要获取ContentResolver 对象,可以使用Activity提供的getContentResolver()方法。 ContentResolver 类提供了与ContentProvider类相同签名的四个方法:
public Uriinsert(Uri uri, ContentValues values)
该方法用于往ContentProvider添加数据。
public int delete(Uri uri, String selection,String[] selectionArgs)
该方法用于从ContentProvider删除数据。
public int update(Uri uri, ContentValues values, Stringselection, String[] selectionArgs)
该方法用于更新ContentProvider中的数据。
public Cursorquery(Uri uri, String[]projection, String selection, String[] selectionArgs, String sortOrder)
该方法用于从ContentProvider中获取数据。
这些方法的第一个参数为Uri,代表要操作的ContentProvider和对其中的什么数据进行操作,假设给定的是:Uri.parse(“content://cn.itcast.providers.personprovider/person/10”),那么将会对主机名为cn.itcast.providers.personprovider的ContentProvider进行操作,操作的数据为person表中id为10的记录。
1、工程结构:
2、内容监听者的清单配置
package cn.huangjie.db;
import cn.huangjie.service.DBOpenHelper;
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
/**
* 内容提供者作为系统中一个类型的组件,一定要放在应用所在包或子包底下
*/
public class PersonProvider extends ContentProvider{
private DBOpenHelper dbOpenHelper;
/**
* UriMatcher需要传入一个数字,传入的数字代表如果跟输入进来的uri不匹配
* 的话那么返回的匹配码,这个输入参数就是不匹配的时候返回出来的不匹配码
*/
private static final UriMatcher MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
//匹配码
private static final int PERSONS = 1;
private static final int PERSON = 2;
static{
MATCHER.addURI("cn.huangjie.provides.personprovider", "person", PERSONS);
//在android中,#代表数字,*代表任意字符
MATCHER.addURI("cn.huangjie.provides.personprovider", "person/#", PERSON);
}
/**
* 该方法由系统调用的,当这个内容提供者的实例被创建出来之后这个方法被调用
*/
@Override
public boolean onCreate() {
dbOpenHelper = new DBOpenHelper(this.getContext());
return true;
}
/**
* 返回你目前要操作数据的内容类型
* 例如:txt,html,mp3
*/
@Override
public String getType(Uri uri) {
switch(MATCHER.match(uri)){
case PERSONS:
return "vnd.android.cursor.dir/";
case PERSON:
return "vnd.android.cursor.item/";
default:
throw new IllegalArgumentException("this is Unknown Uri:" + uri);
}
}
/**
* 允许外部的应用对内容提供者进行插入
*/
@Override
public Uri insert(Uri uri, ContentValues values) {
SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
switch(MATCHER.match(uri)){
case PERSONS:
//返回行号,数据库的RecNo字段不是行号,当行号跟
//如果主键是整型并且是自增长的话那么这个行号是等于主键值
long rowid = db.insert("person", "name", values);
// content://cn.huangjie.provides.personprovider/person/10
//以下两种方式进行拼接的uri都可以
// Uri insertUri = Uri.parse("content://cn.huangjie.provides.personprovider/person/" + rowid);
Uri insertUri = ContentUris.withAppendedId(uri, rowid);
//发出数据变化通知,第二个参数为变化监听者,这里没有监听者
//这样检测此数据的应用会得到相应的通知
this.getContext().getContentResolver().notifyChange(uri, null);
return insertUri;
default:
throw new IllegalArgumentException("this is Unknown Uri:" + uri);
}
}
/**
* 允许外部的应用对内容提供者进行删除
* 返回这个操作所影响的记录数
*/
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
int num = 0;
switch(MATCHER.match(uri)){
case PERSONS:
num = db.delete("person", selection, selectionArgs);
break;
case PERSON:
//解析出/person/10这种形式的id值
long rowid = ContentUris.parseId(uri);
String where = " personid = " + rowid;
if(selection != null && selection.length() > 0){
where += selection;
}
num = db.delete("person", where, selectionArgs);
break;
default:
throw new IllegalArgumentException("this is Unknown Uri:" + uri);
}
return num;
}
/**
* 可以供外部的应用查询内容提供者的数据
*/
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
SQLiteDatabase db = dbOpenHelper.getReadableDatabase();
Cursor cursor = null;
switch(MATCHER.match(uri)){
case PERSONS:
cursor = db.query("person", projection, selection, selectionArgs, null, null, sortOrder);
break;
case PERSON:
//解析出/person/10这种形式的id值
long rowid = ContentUris.parseId(uri);
String where = " personid = " + rowid;
if(selection != null && selection.length() > 0){
where += selection;
}
cursor = db.query("person", projection, where, selectionArgs, null, null, sortOrder);
break;
default:
throw new IllegalArgumentException("this is Unknown Uri:" + uri);
}
return cursor;
}
/**
* 允许外部的应用对内容提供者进行更新
*/
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
int num = 0;
switch(MATCHER.match(uri)){
case PERSONS:
num = db.update("person", values, selection, selectionArgs);
break;
case PERSON:
//解析出/person/10这种形式的id值
long rowid = ContentUris.parseId(uri);
String where = " personid = " + rowid;
if(selection != null && selection.length() > 0){
where += selection;
}
num = db.update("person", values, where, selectionArgs);
break;
default:
throw new IllegalArgumentException("this is Unknown Uri:" + uri);
}
return num;
}
}
package cn.huangjie.test;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.test.AndroidTestCase;
import android.util.Log;
public class ContentProvideTest extends AndroidTestCase{
public void testInsert(){
Uri uri = Uri.parse("content://cn.huangjie.provides.personprovider/person");
//访问内容提供者
ContentResolver resolver = this.getContext().getContentResolver();
ContentValues values = new ContentValues();
values.put("name", "jiehuang");
values.put("age", 545);
resolver.insert(uri, values);
}
public void testDelete(){
Uri uri = Uri.parse("content://cn.huangjie.provides.personprovider/person/30");
//访问内容提供者
ContentResolver resolver = this.getContext().getContentResolver();
int num = resolver.delete(uri, null, null);
Log.i("ContentProvide", "删除影响条数:"+num);
}
public void testUpdate(){
Uri uri = Uri.parse("content://cn.huangjie.provides.personprovider/person/31");
//访问内容提供者
ContentResolver resolver = this.getContext().getContentResolver();
ContentValues values = new ContentValues();
values.put("name", "jieh");
values.put("age", 54);
int num = resolver.update(uri, values, null, null);
Log.i("ContentProvide", "更新影响条数:"+num);
}
public void testQuery(){
Uri uri = Uri.parse("content://cn.huangjie.provides.personprovider/person");
//访问内容提供者
ContentResolver resolver = this.getContext().getContentResolver();
Cursor cursor = resolver.query(uri, null, null, null, "personid desc");
while(cursor.moveToNext()){
int id = cursor.getInt(cursor.getColumnIndex("personid"));
String name = cursor.getString(cursor.getColumnIndex("name"));
Log.i("ContentProvide", id+"#"+name);
}
}
}
2、首先我们需要在内容提供者实现类中增加一个监听的事件
3、在A应用中增加一个按钮,点击按钮往内容提供者中增加一条数据
界面配置文件:
数值配置文件:
Hello World, AappActivity!
A应用
往内容提供者添加数据
package cn.huangjie.aapp;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
public class AappActivity extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
public void insert(View v){
Uri uri = Uri.parse("content://cn.huangjie.provides.personprovider/person");
//访问内容提供者
ContentResolver resolver = this.getContentResolver();
ContentValues values = new ContentValues();
values.put("name", "A_App");
values.put("age", 444);
resolver.insert(uri, values);
}
}
package cn.huangjie.other;
import android.app.Activity;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
public class OtherActivity extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Uri uri = Uri.parse("content://cn.huangjie.provides.personprovider/person");
//第二个参数true表示依赖
this.getContentResolver().registerContentObserver(uri, true,
new PersonContentObserver(new Handler()));
}
private class PersonContentObserver extends ContentObserver{
public PersonContentObserver(Handler handler) {
super(handler);
}
/**
* 这个方法只探测到改变了,但是不知道是修改还是增加还是删除等
* 如果是增加的话则从数据库中读取一条最新的记录便是增加的
*/
@Override
public void onChange(boolean selfChange) {
//sql语句:select * from person order by personid desc limit 1
Uri uri = Uri.parse("content://cn.huangjie.provides.personprovider/person");
Cursor cursor = getContentResolver().query(uri, null, null, null, "personid desc limit 1");
if(cursor.moveToFirst()){//如果有一条记录
String name = cursor.getString(cursor.getColumnIndex("name"));
Log.i("OtherActivity", "检测到的数据:"+name);
}
}
}
}
工程下载:http://download.csdn.net/detail/wxwzy738/6326781