通过ContentObserver监听数据库某表的增加、删除、更新动作,实现listView异步单项Item的刷新

来源:互联网 发布:sql server 2008 sa 编辑:程序博客网 时间:2024/06/05 07:07

如何使用ContentObserver

使用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;        }    }

实现ContentProvider,对数据库的增加、删除、更新动作进行通知

上面实现的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异步对数据库进行增删查操作

若对你还有点用处,那就是本篇文章的意义所在。谢谢。

阅读全文
1 0
原创粉丝点击