想象一個場景: 有個TextView, 用來顯示數據庫一個表的數據總數. 用戶通過UI界面對數據進行CRUD的操作. 這個TextView如何實時監控並更新顯示數據總數?
目錄:
第一節 ContentObserver的感性認識
第二節 3個重點
第三節 具體實現
這裡比較便捷且高效的方案是使用ContentObserver. 前提是已經建立了ContentProvider的支持. 先分析了一些網上廣為流傳了一個監控SMS變化的Observer例子. 畫個圖便於ContentObserver的感性認識.
通過這個圖, 主要了解3點就可以:
1, 建立繼承自ContentObserver的對象,實現其onChange()方法.
2, 在目標Activity中注冊和解除.
3, 在UI線程中, 用Handler接收來自Observer發出的Message, 更新UI.
思路有了, 就看具體的實現了.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
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做的事情. 此例子中是重新查詢表的數據總數.
1 2 3
//注冊觀察者
ContentObserver observer =
new
TAGContentObserver(MainActivity.
this
, mMyHandler);
getContentResolver().registerContentObserver(TAGDBOpenHelper.CONTENT_URI,
true
, observer);
1 2
//解除觀察者
getContentResolver().unregisterContentObserver(observer);
注冊和解除可以根據需要, 比如分別放在Activity的onCreate()和onDestroy()方法中. 關於這個CONTENT_URI, 是自定義的, 如:
1 2 3
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的變化.
1 2 3 4 5 6 7 8 9
@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. 看起來好像齊全了, 其實還有誰在什麼時候通知觀察者數據變化了的問題.
@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就可以實時監控並更新顯示數據總數了.
更多Android相關信息見Android 專題頁面 http://www.linuxidc.com/topicnews.aspx?tid=11