使用ContentObserver的步骤:
1.继承ContentObserver,重载父类的构造方法,实现onChange方法,可根据其中的Uri参数区分不同的动作
2. 注册内容观察者。
context.getContentResolover().registerContentObserver(Uri uri, boolean notifyForDescendents, ContentObserver observer)
功能:为指定的Uri注册一个ContentObserver派生类实例,当给定的Uri发生改变时,回调该实例对象处理。
参数:uri 需要观察的Uri(如:content://example.message/messages 为监听messages表)
notifyForDescendents 为false 表示精确匹配,即只匹配该Uri
为true 表示可以同时匹配其派生的Uri
observer 为自己实现的ContentObserver
注意:此处notifyForDescendents值设置为true,才能做区分增加、删除等动作。
3. 在退出或不需要监听的时候,执行反注册:如在onDestroy()方法中调用public final void unregisterContentObserver(ContentObserver
observer)
功能:取消对给定Uri的观察
参数: observer ContentObserver的派生类实例
参考代码如下:
private class MessageObserver extends ContentObserver {// 自定义ContentObserver
public MessageObserver(Handler handler) {
super(handler);
}
@SuppressLint("NewApi") @Override
public void onChange(boolean selfChange, Uri uri) {
Log.d(TAG, " self change " + selfChange + " Uri " + uri);
// parse Uri, insert, delete, update
int operation = getOperationTypeByUri(uri);//根据Uri获取动作类型(增加、删除等)
mCurrentMessageId = getIdByUri(uri);//根据Uri获取改变的mID
Log.d(TAG, "--operation:"+operation+"--mCurrentMessageId:"+mCurrentMessageId);
doRefreshByOperation(operation,mCurrentMessageId); //执行数据更新操作
super.onChange(selfChange, uri);
}
}
-----------
//根据Uri获取动作类型
private int getOperationTypeByUri(Uri uri){
int operationType = -1;
String strUri = uri.toString();
int endIndex = strUri.lastIndexOf("/");
int beginIndex = endIndex - 6;// insert/update/delete string-size is 6
String type = strUri.substring(beginIndex, endIndex);
Log.d(TAG, "--getOperationTypeByUri--type:"+type);
if(!TextUtils.isEmpty(type)){
if("insert".equals(type)){
operationType = OPERATION_INSERT;
}else if("update".equals(type)){
operationType = OPERATION_UPDATE;
}else if("delete".equals(type)){
operationType = OPERATION_DELETE;
}
}
Log.d(TAG, "--getOperationTypeByUri--operationType:"+operationType);
return operationType;
}
---------------
//根据Uri获取改变的mID
private String getIdByUri(Uri uri){
String id = "";
if(null == uri){
Log.e(TAG, "--getIdbyUri--uri is null, return");
return id;
}
String strUri = uri.toString();
int lastIndex = strUri.lastIndexOf("/");
id = strUri.substring(lastIndex + 1, strUri.length());
Log.d(TAG, "--getIdByUri--id:"+id);
return id;
}
---------------
//根据数据库动作类型,执行不同的操作(此处实现的是聊天页面listView异步刷新单个Item)
private void doRefreshByOperation(int operation, String id){
if(null == mSmsProviderHelp){
Log.e(TAG, "--doRefreshByOperation mSmsProviderHelp is null, return");
return;
}
switch (operation) {
case OPERATION_INSERT:
mSmsProviderHelp.startQueryMessageById(mQueryHandler, SmsProviderHelp.MESSAGES_INSERT_BY_ID_TOKEN, id,mPhoneNumber);//根据mID查询单条数据
break;
case OPERATION_UPDATE:
mSmsProviderHelp.startQueryMessageById(mQueryHandler, SmsProviderHelp.MESSAGES_UPDATE_BY_ID_TOKEN, id,mPhoneNumber);//根据mID查询单条数据
break;
case OPERATION_DELETE:
// delete one from arraylist
int mID = -1;
try {
mID = Integer.parseInt(id);
} catch (NumberFormatException e) {
e.printStackTrace();
}
int deletePosi = mSparseArray.get(mID, -1);
Log.d(TAG, "--deletePosi:"+deletePosi+"--mID:"+mID);
if(deletePosi > -1 && null != mDataList && deletePosi < mDataList.size()){
mDataList.remove(deletePosi);
mMessageAdapter.notifyDataSetChanged();
}
break;
default:
break;
}
}
上面实现的ContentObserver,只是进行监听,当动作变化时需要执行的逻辑放在onChange中。
那么,如何进行通知呢?
答案就是:继承ContentProvider,需要自己实现其中的insert、delete、update方法,发送不同的Uri出去。
参考代码如下:
public class SmsProvider extends ContentProvider {
@Override
public int delete(Uri url, String where, String[] whereArgs) {
String table = TABLE_SMS;
int count;
int match = sURLMatcher.match(url);
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
switch (match) {
case ACTION_SMS:
table = TABLE_SMS;
break;
case ACTION_THREAD:
table = TABLE_THREAD;
break;
default:
throw new IllegalArgumentException("Unknown URL" +url.toString());
}
count = db.delete(table, where, whereArgs);
if (count > 0) {
String rowId = "";
if(null != whereArgs){
rowId = whereArgs[0];
}
Uri deleteUri = Uri.withAppendedPath(url, "delete/"+rowId);//此处为重点,构造了一个Uri发送出去
Log.d(TAG, "--deleteUri:"+deleteUri);
notifyChange(deleteUri);
}
return count;
}
private void notifyChange(Uri uri) {
ContentResolver cr = getContext().getContentResolver();
cr.notifyChange(uri, null);
}
@Override
public Uri insert(Uri url, ContentValues initialValues) {
...
rowID = db.insert(table, "body", values);
if (rowID > 0) {
Uri insertUri = Uri.withAppendedPath(url, "insert/"+rowID);//此处为重点,构造了一个Uri发送出去
Log.d(TAG, "--insertUrl:"+insertUri);
notifyChange(insertUri);
Uri uri = Uri.parse("content://" + table + "/" + rowID);
Log.d(TAG, "insert " + uri + " succeeded");
return uri;
}
@Override
public int update(Uri url, ContentValues values, String where, String[] whereArgs) {
...
count = db.update(table, values, where, whereArgs);
if (count > 0) {
Log.d(TAG, "update " + url + " succeeded"+"values"+values.toString()+"where"+where);
String rowId = "";
if(null != whereArgs){
rowId = whereArgs[0];
}
Uri updateUri = Uri.withAppendedPath(url, "update/"+rowId);//此处为重点,构造了一个Uri发送出去
Log.d(TAG, "--updateUri:"+updateUri);
notifyChange(updateUri);
}
return count;
代码描述:
在delete方法中,判断删除成功时,构造带有“delete/mID”的Uri.
在insert方法中,判断增加成功时,构造带有“insert/mID”的Uri
在update方法中,判断更新成功时,构造带有“update/mID”的Uri
最后通过调用
ContentResolver cr = getContext().getContentResolver();
cr.notifyChange(uri, null);// null表示所有的observer都能收到
发送通知出去。
通过Uri区分不同的数据库动作后。可以根据需要实现不同的功能。
比如:聊天消息页面的异步单项Item刷新流程如下:
流程:
1. 区分message insert update delete 动作,通过messageId查询单条数据
2. 在onchange方法中根据URI区分各种动作。
3. 维护一个map保存position和messageId优化性能
4. 对onChange方法后的刷新逻辑做判断。
@1若为Insert操作,总结起来就是:把数据插入到最后面,调用notifydatasetchanged.
@2.为update操作,根据messageId,单独查询该消息,查询完成后,把该messageId对应的Item数据更新,调用notifidatasetchanged.
@3.为delete操作,根据messageId,找到对应的position,从datalist中remove该Item,调用notifidatasetchanged
另外,可参考另一篇文章:通过AsyncQueryHandler异步对数据库进行增删查操作
若对你还有点用处,那就是本篇文章的意义所在。谢谢。