最近 在學習Android3.0中推出的 Loader 機制,其中CursorLoader 這個加載器說是可以實時監測數據和更新數據,爲了一探究竟,就連帶的將 ContentProvider和Cursor以及CursorAdapter三者間的內部交互分析了下,然而本章內容主要就是將這一塊,至於Loader機制準備,下一篇來具體分析。
對於這三個類我們知道,Contentprovider就是一個Android中進程間的內容共享機制,我們可以使用ContentResolver這個工具嫁接 目標 URI 來訪問對應的Contentprovider,從而獲取目標Cursor數據,Android中 使用Sqliet就是這樣一個機制。然而在這三個類之間其實存在了兩處的觀測者模式的運用。第一處在於Cursor 和 Contentprovider 之間,第二處在於 Cursor 和 CursorAdapter 之間,下面我們先來看一張時序圖大致的瞭解下。Ps: 時序圖 有哪裏不對的還請及時指出啊。
上面說到觀察者模式的運用 第一處在於Cursor 和 Contentprovider 之間,我們可以通過上面的時序圖來加以分析,當我們通過 ContentResolver 對目標ContentProvider的數據進行CRUD(增刪改查)操作時,在返回目標Cursor數據之前,我們發現在每個CRUD操作中有一個setNotifycationUri()這個方法,那麼這個方法裏到底做了什麼呢,我們可以看看。
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;
}
}
複製代碼
我們可以發現,這裏它創建了一個SelfContentObserver的對象並且給它註冊了Uri監聽。這裏SelfContentObserver看起源碼知道了它繼承了ContentObserver,就是一個Observer,這樣一來當Uri變動時,我們就可以通知它了。注意了在我們進行CRUD操作時,我們經常會加一句 :getContext().getContentResolver().notifyChange(XXX.CONTENT_URI,null),那麼這樣一來Cursor類中的mSelfObserver就會收到通知並且回調onChange方法,到這裏我們是不是可以看出來了這就是觀察者模式的運用呢。
至於第二處則在於 Cursor 和 CursorAdapter 之間,同樣的 我們也可從上面的時序圖中發現。CursorAdapter中持有兩個觀察者:mChangeObserver和mDataSetObserver.這兩個Observer在 CursorAdapter初始化時或者調用其changeCursor(Cursor c)或swapCursor(Cursor c)方法時,就被註冊到Cursor中了,三種方式的代碼依次如下:
void init(Context context, Cursor c, int flags) {
...省略
mCursor = c;
...省略
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);
}
}
void init(Context context, Cursor c, int flags) {
...省略
mCursor = c;
...省略
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);
}
}
public Cursor swapCursor(Cursor newCursor) {
if (newCursor == mCursor) {
return null;
}
Cursor oldCursor = mCursor;
if (oldCursor != null) {
if (mChangeObserver != null) oldCursor.unregisterContentObserver(mChangeObserver);
if (mDataSetObserver != null) oldCursor.unregisterDataSetObserver(mDataSetObserver);
}
mCursor = newCursor;
if (newCursor != null) {
if (mChangeObserver != null) newCursor.registerContentObserver(mChangeObserver);
if (mDataSetObserver != null) newCursor.registerDataSetObserver(mDataSetObserver);
mRowIDColumn = newCursor.getColumnIndexOrThrow("_id");
mDataValid = true;
// notify the observers about the new cursor
notifyDataSetChanged();
} else {
mRowIDColumn = -1;
mDataValid = false;
// notify the observers about the lack of a data set
notifyDataSetInvalidated();
}
return oldCursor;
}
我們可以看到,這兩個Observer在初始化Adapter的時候被創建,而後會在不同情況下注冊到Cursor中。這裏是因爲Cursor中持有兩個目標對象:mContentObservable和mDataSetObservable 這兩個類就繼承了Observable接口。所以其實是它們兩分別接受了Observer的註冊。代碼如下:
public void registerContentObserver(ContentObserver observer) {
mContentObservable.registerObserver(observer);
}
public void registerDataSetObserver(DataSetObserver observer) {
mDataSetObservable.registerObserver(observer);
}
到這裏第二處觀察者模式運用就顯示出來啦!
從時序圖中,我們可以看到當Cursor類中的mSelfObserver收到通知後就會調用onChange方法
protected void onChange(boolean selfChange) {
synchronized (mSelfObserverLock) {
mContentObservable.dispatchChange(selfChange);
if (mNotifyUri != null && selfChange) {
mContentResolver.notifyChange(mNotifyUri, mSelfObserver);
}
}
}
我們可以看到 它會觸發mContentObservable這個目標對象去調用dispatchChange()方法
public void dispatchChange(boolean selfChange) {
synchronized(mObservers) {
for (ContentObserver observer : mObservers) {
if (!selfChange || observer.deliverSelfNotifications()) {
observer.dispatchChange(selfChange);
}
}
}
到這裏,它接着就通知其註冊的各個Observer去執行dispatchChange()方法,前面我們已經知道了mContentObservable了被註冊了ChangeObserver 的實例 mChangeObserver,這裏呢首先會執行ChangeObserver的父類ContentObserver的dispatchChange(false)方法:
public final void dispatchChange(boolean selfChange) {
if (mHandler == null) {
onChange(selfChange);
} else {
mHandler.post(new NotificationRunnable(selfChange));
}
}
接着就來到其子類實例mChangeObserver的dispatchChange()方法:
private class ChangeObserver extends ContentObserver {
public ChangeObserver() {
super(new Handler());
}
@Override
public boolean deliverSelfNotifications() {
return true;
}
@Override
public void onChange(boolean selfChange) {
onContentChanged();
}
}
在其Onchange()方法中調用了onContentChanged()方法:
protected void onContentChanged() {
if (mAutoRequery && mCursor != null && !mCursor.isClosed()) {
mDataValid = mCursor.requery();
}
}
到這裏 我們是不是恍然大悟了,mCursor.requery()則就會重新刷新並填充mCursor對象。然後還沒有結束:我們的cursor重新填充了,但是不會告訴Adapter執行notifyDataSetChanged()方法,因爲只有執行了這個方法,我們的界面纔會刷新。
所以我們接着看下mCursor.requery()的內部做了些什麼:
public boolean requery() {
if (mSelfObserver != null && mSelfObserverRegistered == false) {
mContentResolver.registerContentObserver(mNotifyUri, true, mSelfObserver);
mSelfObserverRegistered = true;
}
mDataSetObservable.notifyChanged();
return true;
}
我們可以看到,mDataSetObservable.notifyChanged();這個就會 會觸發mDataSetObservable去通知其內部註冊的observer,前面我們也講了mDataSetObservable被註冊了 CursorAdapter中的 MyDataSetObserver的實例 mDataSetObserver,所以我們接着看下mDataSetObserver的onchange()方法的實現:
private class MyDataSetObserver extends DataSetObserver {
@Override
public void onChanged() {
mDataValid = true;
notifyDataSetChanged();
}
@Override
public void onInvalidated() {
mDataValid = false;
notifyDataSetInvalidated();
}
}
在該方法中調用了 notifyDataSetChanged(); 這個方法幹嘛了呢,我們不僅要問,是不是它就是用來刷新界面呢?這個方法用的是子父類Baseadapter的,
BaseAdapetr
public void notifyDataSetChanged() {
mDataSetObservable.notifyChanged();
}
我們可以看到,在其源碼中,它會調用其父類BaseAdapetr中mDataSetObservable去通知其中被註冊的Observer,那這個observer到底在哪裏被註冊的呢,這裏呢 也就不饒彎子了一步到位,回到我們使用CursorAdapter的最初,但我們初始化完成它的時候,我們是不是接着會調用setAdapter()方法,將該Adapter設置到目標列表中,那麼這裏又做了什麼呢?
public void setAdapter(ListAdapter adapter) {
...省略
if (mAdapter != null) {
...省略
mDataSetObserver = new AdapterDataSetObserver();
mAdapter.registerDataSetObserver(mDataSetObserver);
...省略
requestLayout();
}
在這裏我們找到了我們的答案,原來這個被註冊的observer就是AdapterDataSetObserver,那這下就好啦,我們轉到其內部的onchange()去一探究竟:
public void onChanged() {
mDataChanged = true;
mOldItemCount = mItemCount;
mItemCount = getAdapter().getCount();
// Detect the case where a cursor that was previously invalidated has
// been repopulated with new data.
if (AdapterView.this.getAdapter().hasStableIds() && mInstanceState != null
&& mOldItemCount == 0 && mItemCount > 0) {
AdapterView.this.onRestoreInstanceState(mInstanceState);
mInstanceState = null;
} else {
rememberSyncState();
}
checkFocus();
requestLayout();
}
果不其然,原來它通過 requestLayout();來完成接下來的操作了去刷新界面,其內部就是Android中View的繪製機制了,感興趣的話可以去了解哦!