CursorとCursorAdapterにおける観察者モード機構


転載は出典を明記してください.http://blog.csdn.net/droyon/article/details/9360099
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が提供するフレームワークを合理的に利用すればよい.データをデータベースに挿入した後、自動的にページのリフレッシュを行うことができます.
添付:
Cursor和CursorAdapter中的观察者模式机制_第1张图片