文章摘要:
1壁熄、觀察者模式構(gòu)建松耦合的架構(gòu)敲董,Cursor和CursorAdapter就是其中一個例子,Cursor空另,CursorAdapter配合ListView一起使用盆耽,當(dāng)數(shù)據(jù)發(fā)生改變的時候,可以實(shí)現(xiàn)列表數(shù)據(jù)自動刷新扼菠,不再需要手動執(zhí)行Cursor.requery摄杂。
2、CursorAdapter與Cursor之間通過觀察者之間建立關(guān)系循榆。Cursor是主題析恢,CursorAdapter是觀察者。
ContentProvider與Cursor之間通過Uri之間建立觀察者模式秧饮,ContentProvider是主題映挂,Cursor是觀察者泽篮。
Cursor,CursorAdapter配合ListView一起使用袖肥,當(dāng)數(shù)據(jù)發(fā)生改變的時候咪辱,可以實(shí)現(xiàn)列表數(shù)據(jù)自動刷新≌窭停現(xiàn)在介紹一下內(nèi)中原理椎组。
1、ContentProvider與Cursor之間的關(guān)系历恐。
我們使用Uri向ContentProvider發(fā)起一個query請求用來得到Cursor對象寸癌。但在cursor對象返回之前,我們會給cursor對象執(zhí)行setNotificationUri()方法弱贼。
public Cursor query(Uri uri,String[] projection,String selection,String[] selectionArgs,String sortOrder){
SQLiteDatabase db = mOpenHelper.getReadableDatabase();
Cursor cursor = null;
switch(URI_MATCHER.match(uri)){
case XXX:
break;
case XXX:
break;
..
default:
break;
}
if(cursor != null){
cursor.setNotificationUri(getContext().getContentResolver(), XXX.CONTENT_URI);
}
return cursor;
}
在setNotificationUri方法中執(zhí)行內(nèi)容如下:
類:AbstractCursor.java
public void setNotificationUri(ContentResolver cr, Uri notifyUri) {
synchronized (mSelfObserverLock) {
mNotifyUri = notifyUri;
mContentResolver = cr;
if (mSelfObserver != null) {
mContentResolver.unregisterContentObserver(mSelfObserver);
}
mSelfObserver = new SelfContentObserver(this);
mContentResolver.registerContentObserver(mNotifyUri, true, mSelfObserver);
mSelfObserverRegistered = true;
}
}
在這個方法內(nèi)部蒸苇,首先檢查mSelfObserver是否為null,如果不為null,解除mSelfObserver對uri的監(jiān)聽吮旅。然后重新使用new進(jìn)行實(shí)例化一個mSelfObserver對象溪烤,mSelfObserver繼承自ContentObserver。再然后給mSelfObserver注冊Uri(mNotifyUri)監(jiān)聽庇勃。
protected static class SelfContentObserver extends ContentObserver {
WeakReference<AbstractCursor> mCursor;
public SelfContentObserver(AbstractCursor cursor) {
super(null);
mCursor = new WeakReference<AbstractCursor>(cursor);
}
@Override
public boolean deliverSelfNotifications() {
return false;
}
@Override
public void onChange(boolean selfChange) {
AbstractCursor cursor = mCursor.get();
if (cursor != null) {
cursor.onChange(false);
}
}
}
對以上做一個總結(jié):
在query發(fā)起者得到了一個Cursor對象责嚷,并且這個Cursor對象的實(shí)現(xiàn)類AbstractCursor內(nèi)部會實(shí)例化一個mSelfObserver對象注冊Uri的監(jiān)聽。根據(jù)觀察者模式邏輯罕拂,當(dāng)uri執(zhí)行notify方法時揍异,我們的mSelfObserver會收到通知并且執(zhí)行onChange方法。在這里我們的SelfObserver是觀察者爆班。
2、主題(信息發(fā)布者):通知Cursor中mSelfObserver棍鳖,Uri數(shù)據(jù)發(fā)生改變。
在我們的ContentProvider中的update以及insert或者delete方法中碗旅,我們在方法執(zhí)行的最后按照我們的需求渡处,我們會執(zhí)行如下方法調(diào)用(以update方法為例):
public int update(Uri uri,ContentValues values,String selection,String[] selectionArgs){
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
int affectedRows = 0;
switch(URI_MATCHER.match(uri)){
case XXX:
break;
case XXX:
break;
...
default:
break;
}
if(affectedRows > 0){
getContext().getContentResolver().notifyChange(XXX.CONTENT_URI,null);
}
return affectedRows;
}
當(dāng)我們執(zhí)行方法
getContext().getContentResolver().notifyChange(XXX.CONTENT_URI,null),
那么AbstractCursor類中的mSelfObserver就會收到通知并且回調(diào)onChange方法医瘫。至于在onChange方法中做了那些工作旧困,我們稍后介紹稼锅,我們先來看一下cursor和cursorAdapter之間的關(guān)系僚纷。
3、Cursor和CursorAdapter之間的關(guān)系怖竭。
當(dāng)我們構(gòu)建CursorAdapter時痊臭,我們會將cursor對象作為CursorAdapter的構(gòu)造參數(shù)傳遞到CursorAdapter中。
類:****CursorAdapter.java
public CursorAdapter(Context context, Cursor c, int flags) {
init(context, c, flags);
}
void init(Context context, Cursor c, int flags) {
if ((flags & FLAG_AUTO_REQUERY) == FLAG_AUTO_REQUERY) {
flags |= FLAG_REGISTER_CONTENT_OBSERVER;
mAutoRequery = true;
} else {
mAutoRequery = false;
}
boolean cursorPresent = c != null;
mCursor = c;
mDataValid = cursorPresent;
mContext = context;
mRowIDColumn = cursorPresent ? c.getColumnIndexOrThrow("_id") : -1;
if ((flags & FLAG_REGISTER_CONTENT_OBSERVER) == FLAG_REGISTER_CONTENT_OBSERVER) {
mChangeObserver = new ChangeObserver();
mDataSetObserver = new MyDataSetObserver();
} else {
mChangeObserver = null;
mDataSetObserver = null;
}
if (cursorPresent) {
if (mChangeObserver != null)
c.registerContentObserver(mChangeObserver);
if (mDataSetObserver != null)
c.registerDataSetObserver(mDataSetObserver);
}
}
總結(jié):CursorAdapter通過new關(guān)鍵字初始化了mChangeObserver允趟,mDataSetObserver兩個對象鸦致。并且調(diào)用
c.registerContentObserver(mChangeObserver),c.registerDataSetObserver(mDataSetObserver)抗碰,讓這兩個ContentResolver與Cursor對象建立了聯(lián)系鳍寂。這兩個方法在Cursor中:
類****Cursor.java
public void registerContentObserver(ContentObserver observer) {
mContentObservable.registerObserver(observer);
}
public void registerDataSetObserver(DataSetObserver observer) {
mDataSetObservable.registerObserver(observer);
}
這里涉及到兩個主題類,mContentObservable與mDataSetObservable都繼承自O(shè)bservable捍壤,主題類有如下幾大功能,將觀察者對象加入到列表鞍爱,收到變化時,遍歷列表通知觀察者盗扇。執(zhí)行觀察者對象的onChange方法沉填。
總結(jié):關(guān)于CursorAdapter與Cursor的關(guān)系,我們可以概括一下斑鼻,Cursor中有一套觀察者模式猎荠,其中維護(hù)了兩個主題蜀备,mContentObservable荒叶,mDataSetObservable。在這套觀察者模式中CursorAdapter提供了兩個觀察者對象mChangeObserver脂凶,mDataSetObserver戈毒。當(dāng)Cursor中的主題通知改變的時候横堡,會觸發(fā)執(zhí)行CursorAdapter中的兩個觀察者中的onChanged方法。
4道宅、CursorAdapter和Cursor以及ContentProvider之間的關(guān)系
CursorAdapter與Cursor之間通過觀察者之間建立關(guān)系胸蛛。Cursor是主題,CursorAdapter是觀察者葬项。
ContentProvider與Cursor之間通過Uri之間建立觀察者模式民珍,ContentProvider是主題,Cursor是觀察者嚷量。
5蝶溶、ContentProvider主題發(fā)布通知,Cursor觀察者的邏輯抖所。
Cursor監(jiān)聽的uri發(fā)生了改變(即Cursor中的mSelfObserver接到通知)田轧,業(yè)務(wù)邏輯。
protected static class SelfContentObserver extends ContentObserver {
WeakReference<AbstractCursor> mCursor;
public SelfContentObserver(AbstractCursor cursor) {
super(null);
mCursor = new WeakReference<AbstractCursor>(cursor);
}
@Override
public boolean deliverSelfNotifications() {
return false;
}
@Override
public void onChange(boolean selfChange) {
AbstractCursor cursor = mCursor.get();
if (cursor != null) {
cursor.onChange(false);
}
}
}
我們看一下在Cursor.onChange中的業(yè)務(wù)邏輯:
類:AbstractCursor.java
protected void onChange(boolean selfChange) {
synchronized (mSelfObserverLock) {
mContentObservable.dispatchChange(selfChange);
if (mNotifyUri != null && selfChange) {
mContentResolver.notifyChange(mNotifyUri, mSelfObserver);
}
}
}
執(zhí)行mContentObservable.dispatchChange(false)方法巷查,通過3中可知,執(zhí)行邏輯如下:
類****ContentObservable.java
public void dispatchChange(boolean selfChange) {
synchronized(mObservers) {
for (ContentObserver observer : mObservers) {
if (!selfChange || observer.deliverSelfNotifications()) {
observer.dispatchChange(selfChange);
}
}
}
總結(jié):CursorProvider主題發(fā)送通知旭寿,身為觀察者的Cursor收到變化并執(zhí)行自身的onChange方法崇败。但Cursor也是主題,其收到變化缩膝,會通知其所有的觀察者對象岸霹,也就是CursorAdapter。
6贡避、CursorAdapter中觀察者的邏輯。
類****CursorAdapter$ChangeObserver.java
private class ChangeObserver extends ContentObserver {
public ChangeObserver() {
super(new Handler());
}
@Override
public boolean deliverSelfNotifications() {
return true;
}
@Override
public void onChange(boolean selfChange) {
onContentChanged();
}
}
onContentChanged方法:
protected void onContentChanged() {
if (mAutoRequery && mCursor != null && !mCursor.isClosed()) {
mDataValid = mCursor.requery();
}
}
在這里我們找到了我們的答案湖饱,mCursor.requery(),會重新刷新并填充mCursor對象井厌。
然后還沒有結(jié)束:
我們的cursor重新填充了致讥,但是不會告訴Adapter執(zhí)行notifyDataSetChanged()方法,因?yàn)橹挥袌?zhí)行了這個方法蝇恶,我們的界面才會刷新惶桐。
7、通知Adapter執(zhí)行notifyDataSetChanged()方法姚糊。
當(dāng)我們的Cursor執(zhí)行requery方法的時候,我們看一下業(yè)務(wù)邏輯:
類:****AbstractCursor.java
public boolean requery() {
if (mSelfObserver != null && mSelfObserverRegistered == false) {
mContentResolver.registerContentObserver(mNotifyUri, true, mSelfObserver);
mSelfObserverRegistered = true;
}
mDataSetObservable.notifyChanged();
return true;
}
我們看到我們最后一位主角登場了贸辈,他就是mDataSetObservable肠槽,通過3、可知嘴拢,這是個主題,當(dāng)它notifyChanged的時候赌结,它的所有的觀察者會執(zhí)行onChanged方法孝冒。
我們看一下觀察者的業(yè)務(wù)邏輯:
類:****CursorAdapter$MyDataSetObserver.java
private class MyDataSetObserver extends DataSetObserver {
@Override
public void onChanged() {
mDataValid = true;
notifyDataSetChanged();
}
@Override
public void onInvalidated() {
mDataValid = false;
notifyDataSetInvalidated();
}
}
在onChanged方法中,我們看到了我們的答案量承,notifySetChanged()啼染;
總結(jié):我們在使用Cursor焕梅,CursorAdapter搭配ListView進(jìn)行上層業(yè)務(wù)開發(fā)的過程中,我們只要合理的利用android提供的框架斜棚。我們可以在查詢數(shù)據(jù)庫之后该窗,自動進(jìn)行頁面的刷新。