众所周知,A应用要访问B应用中的数据,最好的方法就是B应用提供给B一些访问接口,然后A通过这个接口来进行对B中的数据进行增删改查
为了统一接口,Android中申明了内容提供者(ContentProvider)这样一个组件,优点是统一了数据的访问方式与提供方式,下面以B应用提供访问接口(ContentProvider)给A应用为例来详细阐述
首先B应用必须写一个类继承自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)}
}
然后B应用必须在清单文件中加入一些代码来进行对该ContentProvider进行唯一的标识
其中android:authorities为PersonContentProvider类的唯一标识(主机名),表示外部应用A可以是通过PersonContentProvider来进行对B中的数据进行操作的
ContentProvider这个接口规定好之后,A应用就可以用它来进行对B应用中数据的访问了
在这里,要操作的数据是URI,URI包括scheml://(内容提供者的唯一标识)主机名/路径...
对URI进行操作的类是contentResolver,他可以通过内容提供者对B应用中的数据进行增删改查,这里就以插入为例
ContentResolver contentResolver =this.getContext().getContentResolver();
Uri insertUri = Uri.parse("content://com.yuchao.providers.personprovider/person");
ContentValues values = new ContentValues();
values.put("name", "zhangsan");
values.put("amount", 90);
Uri uri = contentResolver.insert(insertUri, values);
读者看到最后一句代码可能会莫名其妙,怎么调用了这个方法之后,就可以在B应用中插入一条数据了呢,这里调用的插入方法其实就是B应用中ContentProvider的insert实现方法,代码如下
public Uri insert(Uri uri, ContentValues values){
switch (MATCHER.match(uri)) {
case PERSONS:
SQLiteDatabase db = dbHelper.getWritableDatabase();
long rowid = db.insert("person", "name", values);
Uri insertUri = ContentUris.withAppendedId(uri, rowid);//得到代表新增记录的URI
getContext().getContentResolver().notifyChange(uri, null);//只有注册了该uri才能监听到变化
return insertUri;
default:
throw new IllegalArgumentException("Unknow uri:"+uri.toString());
}
}
通过以上代码可知,A应用要往B应用的数据中添加一条记录,URI必须是"content://com.yuchao.providers.personprovider/person"格式的,我们可以在B应用的ContentProvider定义两种
URI,一种是操作整张表,还有一种是操作某一条数据,添加URI可以通过UriMatcher这个类中的addURI来实现,第三个参数就是MATCHER.match(uri)返回的匹配码,用来识别用户传进来的是
哪种URI,一下是ContentProvider中的内容,目的是添加两条URI
public static final UriMatcher MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
public static final int PERSONS = 1;
public static final int PERSON = 2;
static{
MATCHER.addURI("com.yuchao.providers.personprovider", "person", PERSONS);
MATCHER.addURI("com.yuchao.providers.personprovider", "person/#", PERSON);
}
当然,当调用ContentProvider使得B应用中数据发生变化时,所有注册了ContentProvider的应用还可以监听到B应用中数据的变化,以Insert方法为例,每当新插入数据时,就向所有注册了
该ContentProvider的应用发通知
getContext().getContentResolver().notifyChange(uri, null);//只有注册了该uri才能监听到变化
为了方便,我们写一个Activity来监视此变化
public class OtherActivity extends Activity {
public static final String TAG = "OtherActivity";
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Uri insertUri = Uri.parse("content://com.yuchao.providers.personprovider/person");//B 应用的一个URI
ContentResolver contentResolver = this.getContentResolver();//得到处理URI的对象
contentResolver.registerContentObserver(insertUri, true, new PersonObserver(new Handler()));//注册此URI后调用PersonObserver中的onChange方法
}
public final class PersonObserver extends ContentObserver{
public PersonObserver(Handler handler) {
super(handler);
}
public void onChange(boolean selfChange) {
ContentResolver contentResolver = getContentResolver();
Uri selectUri = Uri.parse("content://com.yuchao.providers.personprovider/person");
Cursor cursor =contentResolver.query(selectUri, null, null, null, "id desc");
while(cursor.moveToNext()){
int id = cursor.getInt(cursor.getColumnIndex("id"));
String name = cursor.getString(cursor.getColumnIndex("name"));
int amount = cursor.getInt(cursor.getColumnIndex("amount"));
Log.i(TAG, "id:"+id+" name:"+name+"aomunt:"+amount);
}
}
}
以上例子就是B应用中数据通过ContentProvider插入后,OtherActivity捕获到这个通知,然后重新获取B应用的数据并打印在控制台上。
至此,ContentProvider的应用介绍完毕!