CursorとCursorAdapterにおける観察者モード機構
11941 ワード
転載は出典を明記してください.http://blog.csdn.net/droyon/article/details/9360099
Cursor,CursorAdapterはListViewと併用し,データが変更されるとリストデータの自動リフレッシュを実現する.内中原理を紹介します.
1、ContentProviderとCursorの関係.
Cursorオブジェクトを取得するためにUriを使用してContentProviderにqueryリクエストを開始します.ただし、cursorオブジェクトが戻る前に、setNotificationUri()メソッドをcursorオブジェクトに実行します.
setNotificationUriメソッドでは、次のように実行されます.
クラス:AbstractCursor.java
この方法の内部では,まずmSelfObserverがnullであるかどうかをチェックし,nullでなければmSelfObserverによるuriの傍受を解除する.次にnewを再使用してmSelfObserverオブジェクトをインスタンス化し、mSelfObserverはContentObserverから継承されます.その後、mSelfObserverにUri(mNotifyUri)リスニングを登録する.
クラス:SelfContentServer.java
要約すると、queryの開始者はCursorオブジェクトを取得し、このCursorオブジェクトの実装クラスAbsstractCursorの内部にはmSelfObserverオブジェクト登録Uriのリスニングがインスタンス化されます.観察者モードロジックによれば,uriがnotifyメソッドを実行すると,我々のmSelfObserverは通知を受け取りonChangeメソッドを実行する.
2、Cursor中のmSelfObserverに、Uriデータが変更されたことを通知する.
ContentProviderのupdateメソッドおよびinsertメソッドまたはdeleteメソッドでは、メソッドの実行の最後に、必要に応じて、updateメソッドを例に、次のメソッド呼び出しを実行します.
実行者がgetContext()を実行するとgetContentResolver().notifyChange(XXX.CONTENT_URI,null)では、AbstraactCursorクラスのmSelfObserverが通知を受け取り、onChangeメソッドをコールバックします.onChangeメソッドでそれらの作業を行ったことについては、後で紹介します.まずcursorとcursorAdapterの関係を見てみましょう.
3、CursorとCursorAdapterの関係.
CursorAdapterを構築すると、cursorオブジェクトをCursorAdapterの構築パラメータとしてCursorAdapterに渡します.
クラス:CursorAdapter.java
まとめ:CursorAdapterは、newキーワードを使用してmChangeObserver、mDataSetObserverの2つのオブジェクトを初期化します.c.registerContentObserver(mChangeObserver)、c.registerDataSetObserver(mDataSetObserver)の2つのメソッドがCursorで呼び出されます.
クラスjava
mContentObservable
はい
ContentObservable
を選択して設定できます.このクラスでは、
クラス:ContentObservable.java
ContentObservableはObservableから継承されており,典型的なオブザーバーモードであり,このクラスは主題クラスである.registerObserverメソッドはContentObserverをリストに追加し、通知を受信するとnotifyChangeメソッドが実行され、このメソッド内ですべてのContentObserverがonChangeメソッドを実行します.
mDataSetObservableは、DataSetObservableのインスタンス化オブジェクトである.このクラスでは、クラス:DataSetObservable.java
同様にObserverから継承されており,同様にオブザーバーにおけるトピックとして登録オブジェクトの変化を通知し,オブジェクトのonChangedメソッドを実行することができる.
まとめ:CursorAdapterとCursorの関係について、Cursorには2つのトピック、mContentObservable、mDataSetObservableを維持する観察者モードがあります.この観察者モードにおいて、CursorAdapterは、2つの観察者mChangeObserver、mDataSetObserverを提供する.Cursorのトピック通知が変更されると、CursorAdapterの2つのオブザーバーのonChangedメソッドが実行されます.
4、CursorAdapterとCursor、ContentProviderの関係
CursorAdapterとCursorの間には観察者間の関係が確立されている.
ContentProviderとCursorの間にはUriの関係があります.
5.Cursorが傍受するuriが変更された場合(すなわち、CursorのmSelfObserverが通知を受ける)、ビジネスロジック.
cursorが実行されます.onChange(false);
onChangeでのビジネスロジックを見てみましょう.
クラス:AbstractCursor.java
mContentObservableを実行する.dispatchChange(false)メソッドは,3で分かるように,実行ロジックは次のようになる.
クラスContentObservable.java
登録されたすべてのオブザーバーのdispatchChange(false)メソッドが実行されます.
dispatchChange(false)でのビジネスロジック:
6,5,でトリガされた観察者のdispatchChange(false)メソッドにおけるビジネスロジック
まず、ChangeObserverの親ContentObserverのdispatchChangeメソッドが実行されます.
クラス:ContentObserver.java
onChange(false)が実行されるのを見ました.
クラスCursorAdapter$ChangeObserver.java
その後、onContentChanged()メソッドが実行されます.
ここで私たちの答えを見つけました
mCursor.requery(),
再更新して塗りつぶします
mCursor
オブジェクト.
そしてまだ終わっていません:
我々のcursorは再充填されたが、AdapterにnotifyDataSetChanged()メソッドを実行するようには言わない.このメソッドを実行してこそ、我々のインタフェースがリフレッシュされるからだ.
7、AdapterにnotifyDataSetChanged()メソッドの実行を通知する.
Cursorがrequeryメソッドを実行するとき、ビジネスロジックを見てみましょう.
クラス:AbstractCursor.java
私たちの最後の主役が登場したのを見て、彼はmDataSetObservableで、3、これはテーマで、notifyChangedの時、そのすべての観察者はonChanged方法を実行します.
観察者のビジネスロジックを見てみましょう.
クラス:CursorAdapter$MyDataSetObserver.java
にある
onChanged
方法では、私たちの答えを見ました.
notifySetChanged
();
まとめ:Cursor,CursorAdapterをListViewと組み合わせて上位ビジネス開発を行う過程で,androidが提供するフレームワークを合理的に利用すればよい.データをデータベースに挿入した後、自動的にページのリフレッシュを行うことができます.
添付:
Cursor,CursorAdapterはListViewと併用し,データが変更されるとリストデータの自動リフレッシュを実現する.内中原理を紹介します.
1、ContentProviderとCursorの関係.
Cursorオブジェクトを取得するためにUriを使用してContentProviderにqueryリクエストを開始します.ただし、cursorオブジェクトが戻る前に、setNotificationUri()メソッドをcursorオブジェクトに実行します.
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メソッドでは、次のように実行されます.
クラス: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;
}
}
この方法の内部では,まずmSelfObserverがnullであるかどうかをチェックし,nullでなければmSelfObserverによるuriの傍受を解除する.次にnewを再使用してmSelfObserverオブジェクトをインスタンス化し、mSelfObserverはContentObserverから継承されます.その後、mSelfObserverにUri(mNotifyUri)リスニングを登録する.
クラス:SelfContentServer.java
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);
}
}
}
要約すると、queryの開始者はCursorオブジェクトを取得し、このCursorオブジェクトの実装クラスAbsstractCursorの内部にはmSelfObserverオブジェクト登録Uriのリスニングがインスタンス化されます.観察者モードロジックによれば,uriがnotifyメソッドを実行すると,我々のmSelfObserverは通知を受け取りonChangeメソッドを実行する.
2、Cursor中のmSelfObserverに、Uriデータが変更されたことを通知する.
ContentProviderのupdateメソッドおよびinsertメソッドまたはdeleteメソッドでは、メソッドの実行の最後に、必要に応じて、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;
}
実行者がgetContext()を実行するとgetContentResolver().notifyChange(XXX.CONTENT_URI,null)では、AbstraactCursorクラスのmSelfObserverが通知を受け取り、onChangeメソッドをコールバックします.onChangeメソッドでそれらの作業を行ったことについては、後で紹介します.まずcursorとcursorAdapterの関係を見てみましょう.
3、CursorとCursorAdapterの関係.
CursorAdapterを構築すると、cursorオブジェクトをCursorAdapterの構築パラメータとして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);
}
}
まとめ:CursorAdapterは、newキーワードを使用してmChangeObserver、mDataSetObserverの2つのオブジェクトを初期化します.c.registerContentObserver(mChangeObserver)、c.registerDataSetObserver(mDataSetObserver)の2つのメソッドがCursorで呼び出されます.
クラスjava
public void registerContentObserver(ContentObserver observer) {
mContentObservable.registerObserver(observer);
}
public void registerDataSetObserver(DataSetObserver observer) {
mDataSetObservable.registerObserver(observer);
}
mContentObservable
はい
ContentObservable
を選択して設定できます.このクラスでは、
クラス:ContentObservable.java
public class ContentObservable extends Observable<ContentObserver> {
@Override
public void registerObserver(ContentObserver observer) {
super.registerObserver(observer);
}
public void dispatchChange(boolean selfChange) {
synchronized(mObservers) {
for (ContentObserver observer : mObservers) {
if (!selfChange || observer.deliverSelfNotifications()) {
observer.dispatchChange(selfChange);
}
}
}
}
public void notifyChange(boolean selfChange) {
synchronized(mObservers) {
for (ContentObserver observer : mObservers) {
observer.onChange(selfChange);
}
}
}
}
ContentObservableはObservableから継承されており,典型的なオブザーバーモードであり,このクラスは主題クラスである.registerObserverメソッドはContentObserverをリストに追加し、通知を受信するとnotifyChangeメソッドが実行され、このメソッド内ですべてのContentObserverがonChangeメソッドを実行します.
mDataSetObservableは、DataSetObservableのインスタンス化オブジェクトである.このクラスでは、クラス:DataSetObservable.java
public class DataSetObservable extends Observable<DataSetObserver> {
public void notifyChanged() {
synchronized(mObservers) {
for (int i = mObservers.size() - 1; i >= 0; i--) {
mObservers.get(i).onChanged();
}
}
}
public void notifyInvalidated() {
synchronized (mObservers) {
for (int i = mObservers.size() - 1; i >= 0; i--) {
mObservers.get(i).onInvalidated();
}
}
}
}
同様にObserverから継承されており,同様にオブザーバーにおけるトピックとして登録オブジェクトの変化を通知し,オブジェクトのonChangedメソッドを実行することができる.
まとめ:CursorAdapterとCursorの関係について、Cursorには2つのトピック、mContentObservable、mDataSetObservableを維持する観察者モードがあります.この観察者モードにおいて、CursorAdapterは、2つの観察者mChangeObserver、mDataSetObserverを提供する.Cursorのトピック通知が変更されると、CursorAdapterの2つのオブザーバーのonChangedメソッドが実行されます.
4、CursorAdapterとCursor、ContentProviderの関係
CursorAdapterとCursorの間には観察者間の関係が確立されている.
ContentProviderとCursorの間にはUriの関係があります.
5.Cursorが傍受するuriが変更された場合(すなわち、CursorのmSelfObserverが通知を受ける)、ビジネスロジック.
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(false);
onChangeでのビジネスロジックを見てみましょう.
クラス:AbstractCursor.java
protected void onChange(boolean selfChange) {
synchronized (mSelfObserverLock) {
mContentObservable.dispatchChange(selfChange);
if (mNotifyUri != null && selfChange) {
mContentResolver.notifyChange(mNotifyUri, mSelfObserver);
}
}
}
mContentObservableを実行する.dispatchChange(false)メソッドは,3で分かるように,実行ロジックは次のようになる.
クラスContentObservable.java
public void dispatchChange(boolean selfChange) {
synchronized(mObservers) {
for (ContentObserver observer : mObservers) {
if (!selfChange || observer.deliverSelfNotifications()) {
observer.dispatchChange(selfChange);
}
}
}
登録されたすべてのオブザーバーのdispatchChange(false)メソッドが実行されます.
dispatchChange(false)でのビジネスロジック:
6,5,でトリガされた観察者のdispatchChange(false)メソッドにおけるビジネスロジック
まず、ChangeObserverの親ContentObserverのdispatchChangeメソッドが実行されます.
クラス:ContentObserver.java
public final void dispatchChange(boolean selfChange) {
if (mHandler == null) {
onChange(selfChange);
} else {
mHandler.post(new NotificationRunnable(selfChange));
}
}
onChange(false)が実行されるのを見ました.
クラス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
オブジェクト.
そしてまだ終わっていません:
我々のcursorは再充填されたが、AdapterにnotifyDataSetChanged()メソッドを実行するようには言わない.このメソッドを実行してこそ、我々のインタフェースがリフレッシュされるからだ.
7、AdapterにnotifyDataSetChanged()メソッドの実行を通知する.
Cursorがrequeryメソッドを実行するとき、ビジネスロジックを見てみましょう.
クラス:AbstractCursor.java
public boolean requery() {
if (mSelfObserver != null && mSelfObserverRegistered == false) {
mContentResolver.registerContentObserver(mNotifyUri, true, mSelfObserver);
mSelfObserverRegistered = true;
}
mDataSetObservable.notifyChanged();
return true;
}
私たちの最後の主役が登場したのを見て、彼はmDataSetObservableで、3、これはテーマで、notifyChangedの時、そのすべての観察者はonChanged方法を実行します.
観察者のビジネスロジックを見てみましょう.
クラス:CursorAdapter$MyDataSetObserver.java
private class MyDataSetObserver extends DataSetObserver {
@Override
public void onChanged() {
mDataValid = true;
notifyDataSetChanged();
}
@Override
public void onInvalidated() {
mDataValid = false;
notifyDataSetInvalidated();
}
}
にある
onChanged
方法では、私たちの答えを見ました.
notifySetChanged
();
まとめ:Cursor,CursorAdapterをListViewと組み合わせて上位ビジネス開発を行う過程で,androidが提供するフレームワークを合理的に利用すればよい.データをデータベースに挿入した後、自動的にページのリフレッシュを行うことができます.
添付: