想象一个场景: 有个TextView, 用来显示数据库一个表的数据总数. 用户通过UI界面对数据进行CRUD的操作. 这个TextView如何实时监控并更新显示数据总数?
目录:
第一节 ContentObserver的感性认识
第二节 3个重点
第三节 具体实现
这里比较便捷且高效的方案是使用ContentObserver. 前提是已经建立了ContentProvider的支持. 先分析了一些网上广为流传了一个监控SMS变化的Observer例子. 画个图便于ContentObserver的感性认识.
通过这个图, 主要了解3点就可以:
1, 建立继承自ContentObserver的对象,实现其onChange()方法.
2, 在目标Activity中注册和解除.
3, 在UI线程中, 用Handler接收来自Observer发出的Message, 更新UI.
思路有了, 就看具体的实现了.
一. 首先是建立一个继承自ContentObserver的对象.
public class TAGContentObserver extends ContentObserver{
private Context mContext;
private Handler mHandler;
public static final int TAG_DB_CHANGE = 921;
public TAGContentObserver(Context context, Handler handler) {
super(handler);
mContext = context;
mHandler = handler;
}
@Override
public void onChange(boolean selfChange) {
//数据变化, 重新查询最新结果.
Cursor cursor = mContext.getContentResolver().query(TAGDBOpenHelper.CONTENT_URI, null, null, null, null);
//发送Message. 此Handler定义在Activity中, 拆开Message得到结果更新TextView.
mHandler.obtainMessage(TAG_DB_CHANGE, cursor.getCount(), 0).sendToTarget();
}
}
重点是实现其onChange()方法, 如注释所写. onChange可以理解为在得到数据变化的通知之后, Observer做的事情. 此例子中是重新查询表的数据总数.
二. 在Activity中注册和解除.
//注册观察者
ContentObserver observer = new TAGContentObserver(MainActivity.this, mMyHandler);
getContentResolver().registerContentObserver(TAGDBOpenHelper.CONTENT_URI, true, observer);
//解除观察者
getContentResolver().unregisterContentObserver(observer);
注册和解除可以根据需要, 比如分别放在Activity的onCreate()和onDestroy()方法中. 关于这个CONTENT_URI, 是自定义的, 如:
public static final String TABLE_NAME_TAG = "tag";
public static final String AUTHORITY = "com.lichen.tagprovider";
public static final Uri CONTENT_URI = Uri.parse("content://"+TAGDBOpenHelper.AUTHORITY+"/"+TABLE_NAME_TAG);
此Observer的目的可以说是监听或者观察这个URI的变化.
三. 在UI线程中, 用Handler接收来自Observer发出的Message, 更新UI.
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case TAGContentObserver.TAG_DB_CHANGE:
TextView tagNum = (TextView) findViewById(R.id.tag_total_num);
tagNum.setText("TAG总数: " + msg.arg1);
break;
}
}
到这里, 注册观察者Observer, 数据变化后重新查询数据库, 得到结果异步用Handler来更新UI. 看起来好像齐全了, 其实还有谁在什么时候通知观察者数据变化了的问题.
四. 在ContentProvider中添加通知数据变化.
@Override
public Uri insert(Uri uri, ContentValues values) {
db = dbHelper.getWritableDatabase();
long rowId = db.insert(TAGDBOpenHelper.TABLE_NAME_TAG, "", values);
if (rowId > 0) {
Uri newUrl = ContentUris.withAppendedId(TAGDBOpenHelper.CONTENT_URI, rowId);
//通知数据变化
getContext().getContentResolver().notifyChange(newUrl, null);
return newUrl;
}
return null;
}
@Override
public int delete(Uri uri, String where, String[] whereArgs) {
db = dbHelper.getWritableDatabase();
int count = 0;
switch (matcher.match(uri)) {
case TAGDBOpenHelper.TAG:
count = db.delete(TAGDBOpenHelper.TABLE_NAME_TAG, where, whereArgs);
break;
case TAGDBOpenHelper.TAG_ID:
long parseId = ContentUris.parseId(uri);
where = " _id = " + parseId ;
count = db.delete(TAGDBOpenHelper.TABLE_NAME_TAG, where, null);
break;
}
//通知数据变化
getContext().getContentResolver().notifyChange(uri, null);
return count;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
db = dbHelper.getReadableDatabase();
int match = matcher.match(uri);
Cursor cursor = null;
switch (match) {
case TAGDBOpenHelper.TAG:
cursor = db.query(TAGDBOpenHelper.TABLE_NAME_TAG, null, null, null, null, null, null);
cursor.setNotificationUri(getContext().getContentResolver(), uri);//通知数据变化
break;
}
return cursor;
}
这样, 这个TextView就可以实时监控并更新显示数据总数了.