Android数据库内容变化的监听

首先介绍内容监测的基本模式
uri 的内容监测的基本模式被 android.content.ContentResolver 实现
它为基于Uri的内容监测的提供了一个平台。(其实如果有必要,我们可以自己实现一个)
ContentResolver 为此提供了三个方法:
注册监听器到某个 uri
public final void   registerC首先介绍内容监测的基本模式
uri的内容监测的基本模式被android.content.ContentResolver实现
它为基于Uri的内容监测的提供了一个平台。(其实如果有必要,我们可以自己实现一个)
ContentResolver为此提供了三个方法:
注册监听器到某个uri
public final void registerContentObserver (Uri uri, boolean notifyForDescendents, ContentObserver observer)
Register an observer class that gets callbacks when data identified by a given content URI changes.
Parameters
uri     The URI to watch for changes. This can be a specific row URI, or a base URI for a whole class of content.
notifyForDescendents     If true changes to URIs beginning with uri will also cause notifications to be sent. 
    If false only changes to the exact URI specified by uri will cause notifications to be sent. 
    If true, than any URI values at or below the specified URI will also trigger a match.
observer     The object that receives callbacks when changes occur.
取消被注册的监听器
public final void unregisterContentObserver (ContentObserver observer)
Unregisters a change observer.
参数
observer     The previously registered observer that is no longer needed.
通知所有注册到uri的监听器,告诉他们内容发生了改变。
public void notifyChange (Uri uri, ContentObserver observer)
Notify registered observers that a row was updated. To register, call registerContentObserver(). By default, CursorAdapter objects will get this notification.
参数
observer     The observer that originated the change, may be null .用以说明observer是第一个发现内容改变的ContentObserver,可为null.
通知所有注册到uri的监听器,告诉他们内容发生了改变。
public void notifyChange (Uri uri, ContentObserver observer, boolean syncToNetwork)
Notify registered observers that a row was updated. To register, call registerContentObserver(). By default, CursorAdapter objects will get this notification.
参数
observer     The observer that originated the change, may be null 用以说明observer是第一个发现内容改变的ContentObserver,可为null
syncToNetwork     If true, attempt to sync the change to the network. 
注1:"基于uri的内容监测的基本模式被android.content.ContentResolver实现",严格来说ContentResolver至少提供了接口。
真正的实现在android.content.ContentService.
其实ContentResolver为基于Uri的内容监测所提供的方法只是调用ContentService相关的方法
注2:"注册监听器到uri"只是说如果notifyChangeuriregisterContentObserver中的uri相匹配,则调用observer的方法onChange
内容监听器ContentObserver主要有三个方法
public boolean deliverSelfNotifications ()
Returns true if this observer is interested in notifications for changes made through the cursor the observer is registered with.
注:这个函数的使用还是puzzle.
public final void dispatchChange (boolean selfChange)
注:这个是为提供用handler执行onChange的一个接口。所以一般比没必要重载它。
public void onChange (boolean selfChange)
This method is called when a change occurs to the cursor that is being observed.
参数
selfChange     true if the update was caused by a call to commit on the cursor that is being observed. 
注1:这个就是我们需要重载的函数,在里面可以实现对内容改变的个性化响应。
关于ContentObserver的更多内容请参阅《内容监听器ContentObserver》。
基本使用是这样的:
首先使用registerContentObserver注册observer监听器到uri,然后在内容发生改变时,就调用notifyChange通知系统所有注册到该uri的监听器,告诉他们内容发生了改变。
这时相应的监听器的dispatchChange方法被调用,在dispatchChange中onChange被调用。
最后如果不想让observer监听器uri相关的内容监听,可以调用unregisterContentObserver来取消注册

对数据库改变的监测是如何实现的呢?
在providers对数据进行改变后,会通过getContext().getContentResolver().notifyChange的发生相应的uri的内容发生了改变
比如:com.android.providers.contacts中的ContactsProvider2
ContactsProvider2.java文件
public class ContactsProvider2 extends SQLiteContentProvider implements OnAccountsUpdateListener {
-------------------省略------------------
  @Override
    public Uri insert(Uri uri, ContentValues values) {
        waitForAccess();
        return super.insert(uri, values);
    }
    @Override
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
-------------------省略------------------
        waitForAccess();
        return super.update(uri, values, selection, selectionArgs);
    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        waitForAccess();
        return super.delete(uri, selection, selectionArgs);
    }
}
-------------------省略------------------
    protected void notifyChange() {
        notifyChange(mSyncToNetwork);
        mSyncToNetwork = false;
    }

    protected void notifyChange(boolean syncToNetwork) {
        getContext().getContentResolver().notifyChange(ContactsContract.AUTHORITY_URI, null,
                syncToNetwork);
    }
    -------------------省略------------------
}
SQLiteContentProvider.java文件
public abstract class SQLiteContentProvider extends ContentProvider
        implements SQLiteTransactionListener {
   @Override
    public Uri insert(Uri uri, ContentValues values) {
        Uri result = null;
        boolean applyingBatch = applyingBatch();
        if (!applyingBatch) {
            mDb = mOpenHelper.getWritableDatabase();
            mDb.beginTransactionWithListener(this);
            try {
                result = insertInTransaction(uri, values);
                if (result != null) {
                    mNotifyChange = true;
                }
                mDb.setTransactionSuccessful();
            } finally {
                mDb.endTransaction();
            }

            onEndTransaction();
        } else {
            result = insertInTransaction(uri, values);
            if (result != null) {
                mNotifyChange = true;
            }
        }
        return result;
    }
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
        -------------------省略------------------
    }
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        -------------------省略------------------
    }
 -------------------省略------------------
 protected abstract void notifyChange();
 -------------------省略------------------
    protected void onEndTransaction() {
        if (mNotifyChange) {
            mNotifyChange = false;
            notifyChange();
        }
    }
 -------------------省略------------------
}
那么Cursor是如何实现对基于uri的数据库内容变化进行监听呢?
只要把一个监听器ContentObserver对uri使用ContentResolver的
registerContentObserver方法进行注册。
如果相应
uri的数据库内容变化发变化,先通知ContentObserver,再又让它通知Cursor。
当然为了方便系统把ContentObserver设计成了内部类
具体可见在Cursor接口的一个实现android.database.AbstractCursor
AbstractCursor.java文件请见附件1
同时Cursor为我们提供了setNotificationUri(ContentResolver cr, Uri notifyUri)让它内部类的ContentObserver注册到ContentResolver的某个Uri上.
具体代码参见附件1
那么外部如何监听Cursor呢?。
Cursor为外部监测数据库的变化提供了以下接口:
abstract void     registerContentObserver(ContentObserver observer)
Register an observer that is called when changes happen to the content backing this cursor.
注1:当数据库内容变化时通知observer,具体见附件1的onChange(boolean selfChange)函数.
注2:这个监听器observer主要是在setNotificationUri(ContentResolver cr, Uri notifyUri)中notifyUri对应的数据库内容发生变化时被通知的(间接),
abstract void     unregisterContentObserver(ContentObserver observer)
Unregister an observer that has previously been registered with this cursor via registerContentObserver(ContentObserver).
另外, Cursor 还为我们提供了接口,让外部可以通过注册一个 DataSetObserver 来对Cursor的 requery(), deactivate(), close() 行为进行监听。
abstract void      registerDataSetObserver (DataSetObserver observer)
Register an observer that is called when changes happen to the contents of the this cursors data set, for example, when the data set is changed via requery(), deactivate(), or close().
注1:当Cursor发生requery(), deactivate(), or close()时通知DataSetObserver observer
abstract void      unregisterDataSetObserver (DataSetObserver observer)
Unregister an observer that has previously been registered with this cursor via registerContentObserver(ContentObserver).
DataSetObserver 的主要方法
Public Methods
void onChanged()
This method is called when the entire data set has changed, most likely through a call to  requery() on a  Cursor.
void onInvalidated()
This method is called when the entire data becomes invalid, most likely through a call to  deactivate() or  close() on a  Cursor.
那么 CursorAdapter 是如何实现对基于 uri 的数据库内容变化进行监听呢?
它当然是 借助Cursor 来实现的。
但是 CursorAdapterContentObserver相对应对外提供(可以重载)的接口是:
onContentChanged()
当时 CursorAdapterDataSetObserver相对应对外提供(可以重载)的接口是:
onChanged()->notifyDataSetChanged() //这个消息并完全不是从Cursor传递来,它会在CursorAdapter内手动被调用
onInvalidated()->notifyDataSetInvalidated() //这个消息并不是从Cursor传递来。
具体可以参照 附件2的android.widget.CursorAdapter源代码
CursorAdapternotifyDataSetChanged()notifyDataSetInvalidated()事件 可以 继续往外传递
BaseAdapter为此提供了以下系列方法。
void notifyDataSetChanged()
Notifies the attached observers that the underlying data has been changed and any View reflecting the data set should refresh itself.
void notifyDataSetInvalidated()
Notifies the attached observers that the underlying data is no longer valid or available.
void registerDataSetObserver( DataSetObserver observer)
Register an observer that is called when changes happen to the data used by this adapter.
void unregisterDataSetObserver( DataSetObserver observer)
Unregister an observer that has previously been registered with this adapter via  registerDataSetObserver(DataSetObserver).
android.widget.BaseAdapter的部分源代码如下:
public abstract class   BaseAdapter   implements  ListAdapter, SpinnerAdapter { 
private final  DataSetObservable mDataSetObservable = new DataSetObservable(); 
public boolean hasStableIds() { return false; } 
public void   registerDataSetObserver (DataSetObserver observer) { mDataSetObservable.registerObserver(observer); } 
public void  unregisterDataSetObserver (DataSetObserver observer) { mDataSetObservable.unregisterObserver(observer); } 
/** * Notifies the attached View that the underlying data has been changed * and it should refresh itself. */ 
public void  notifyDataSetChanged()  { mDataSetObservable.notifyChanged(); } 
public void  notifyDataSetInvalidated()  { mDataSetObservable.notifyInvalidated(); } 
-------------------省略------------------
注意:对于 BaseAdapter,外部可以强行调用 notifyDataSetChangednotifyDataSetInvalidated来通知DataSetObserver observer

ontentObserver
 (Uri uri, boolean notifyForDescendents, ContentObserver observer)
Register an observer class that gets callbacks when data identified by a given content URI changes.
Parameters
uri     The URI to watch for changes. This can be a specific row URI, or a base URI for a whole class of content.
notifyForDescendents     If true changes to URIs beginning with uri will also cause notifications to be sent. 
    If false only changes to the exact URI specified by uri will cause notifications to be sent. 
    If true, than any URI values at or below the specified URI will also trigger a match.
observer     The object that receives callbacks when changes occur.
取消被注册的监听器
public final void   unregisterContentObserver  (ContentObserver observer)
Unregisters a change observer.
参数
observer     The previously registered observer that is no longer needed.
通知所有注册到uri的监听器,告诉他们内容发生了改变。
public void   notifyChange   (Uri uri, ContentObserver  observer )
Notify registered observers that a row was updated. To register, call registerContentObserver(). By default, CursorAdapter objects will get this notification.
参数
observer     The observer that originated the change, may be null .用以说明 observer 是第一个发现内容改变的ContentObserver,可为null.
通知所有注册到uri的监听器,告诉他们内容发生了改变。
public void  notifyChange  (Uri uri, ContentObserver observer, boolean syncToNetwork)
Notify registered observers that a row was updated. To register, call registerContentObserver(). By default, CursorAdapter objects will get this notification.
参数
observer     The observer that originated the change, may be null 用以说明 observer 是第一个发现内容改变的ContentObserver,可为null
syncToNetwork     If true, attempt to sync the change to the network. 
注1 :"基于uri的内容监测的基本模式被android.content.ContentResolver实现",严格来说ContentResolver至少提供了接口。
真正的实现在android.content.ContentService.
其实ContentResolver为基于Uri的内容监测所提供的方法只是调用ContentService相关的方法
注2 : "注册监听器到 uri "只是说如果 notifyChange uri registerContentObserver 中的 uri 相匹配,则调用 observer 的方法 onChange
内容监听器 ContentObserver 主要有三个方法
public boolean   deliverSelfNotifications ()
Returns true if this observer is interested in notifications for changes made through the cursor the observer is registered with.
注:这个函数的使用还是puzzle.
public final void   dispatchChange  (boolean selfChange)
注:这个是为提供用handler执行onChange的一个接口。所以一般比没必要重载它。
public void   onChange  (boolean selfChange)
This method is called when a change occurs to the cursor that is being observed.
参数
selfChange     true if the update was caused by a call to commit on the cursor that is being observed. 
注1:这个就是我们需要重载的函数,在里面可以实现对内容改变的个性化响应。
关于ContentObserver的更多内容请参阅《 内容监听器ContentObserver 》。
基本使用是这样的:
首先使用 registerContentObserver 注册 observer 监听器到 uri ,然后在内容发生改变时,就调用 notifyChange 通知系统所有注册到该 uri 的监听器 ,告诉他们内容发生了改变。
这时相应的监听器的dispatchChange方法被调用,在dispatchChange中onChange被调用。
最后如果不想让 observer 监听器 uri 相关的内容监听,可以调用 unregisterContentObserve r来取消注册

对数据库改变的监测是如何实现的呢?
在providers对数据进行改变后,会通过 getContext().getContentResolver().notifyChange 的发生相应的uri的内容发生了改变
比如:com.android.providers.contacts中的ContactsProvider2
ContactsProvider2.java文件
public class   ContactsProvider2  extends  SQLiteContentProvider implements OnAccountsUpdateListener {
-------------------省略------------------
  @Override
    public Uri insert(Uri uri, ContentValues values) {
        waitForAccess();
        return super.insert(uri, values);
    }
    @Override
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
-------------------省略------------------
        waitForAccess();
        return super.update(uri, values, selection, selectionArgs);
    }

     @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        waitForAccess();
        return super.delete(uri, selection, selectionArgs);
    }
}
-------------------省略------------------
     protected void   notifyChange()  {
        notifyChange(mSyncToNetwork);
        mSyncToNetwork = false;
    }

     protected void   notifyChange (boolean syncToNetwork) {
        getContext().getContentResolver().notifyChange(ContactsContract.AUTHORITY_URI, null,
                syncToNetwork);
    }
    -------------------省略------------------
}
SQLiteContentProvider.java文件
public abstract class   SQLiteContentProvider  extends  ContentProvider
        implements SQLiteTransactionListener {
   @Override
    public Uri insert(Uri uri, ContentValues values) {
        Uri result = null;
        boolean applyingBatch = applyingBatch();
        if (!applyingBatch) {
            mDb = mOpenHelper.getWritableDatabase();
            mDb.beginTransactionWithListener(this);
            try {
                result = insertInTransaction(uri, values);
                if (result != null) {
                    mNotifyChange = true;
                }
                mDb.setTransactionSuccessful();
            } finally {
                mDb.endTransaction();
            }

             onEndTransaction();
        } else {
            result = insertInTransaction(uri, values);
            if (result != null) {
                mNotifyChange = true;
            }
        }
        return result;
    }
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
        -------------------省略------------------
    }
    public int delete(Uri uri, String selection, String[] selectionArgs) {
         -------------------省略------------------
    }
 -------------------省略------------------
 protected abstract void   notifyChange();
 -------------------省略------------------
    protected void   onEndTransaction()  {
         if  (mNotifyChange) {
            mNotifyChange = false;
              notifyChange ();
        }
    }
 -------------------省略------------------
}
那么Cursor是如何实现对基于uri的数据库内容变化进行监听呢?
只要把一个监听器ContentObserver对uri使用ContentResolver的
registerContentObserver 方法进行注册。
如果相应
uri 的数据库内容变化发变化,先通知 ContentObserver ,再又让它通知Cursor。
当然为了方便系统把ContentObserver设计成了 内部类
具体可见在Cursor接口的一个实现 android.database.AbstractCursor
AbstractCursor.java文件请见 附件1
同时Cursor为我们提供了 setNotificationUri (ContentResolver cr, Uri notifyUri)让它内部类的 ContentObserver 注册 到ContentResolver的某个 Uri 上.
具体代码参见 附件1
那么外部如何 监听Cursor 呢?。
Cursor 为外部监测数据库的变化提供了以下接口:
abstract void      registerContentObserver (ContentObserver observer)
Register an observer that is called when changes happen to the content backing this cursor.
注1:当数据库内容变化时通知observer,具体见 附件1 的onChange(boolean selfChange)函数.
注2:这个监听器observer主要是在 setNotificationUri(ContentResolver cr, Uri notifyUri) 中notifyUri对应的数据库内容发生变化时被通知的(间接),
abstract void      unregisterContentObserver (ContentObserver observer)
Unregister an observer that has previously been registered with this cursor via registerContentObserver(ContentObserver).
另外, Cursor 还为我们提供了接口,让外部可以通过注册一个 DataSetObserver 来对Cursor的 requery(), deactivate(), close() 行为进行监听。
abstract void      registerDataSetObserver (DataSetObserver observer)
Register an observer that is called when changes happen to the contents of the this cursors data set, for example, when the data set is changed via requery(), deactivate(), or close().
注1:当Cursor发生requery(), deactivate(), or close()时通知DataSetObserver observer
abstract void      unregisterDataSetObserver (DataSetObserver observer)
Unregister an observer that has previously been registered with this cursor via registerContentObserver(ContentObserver).
DataSetObserver 的主要方法
Public Methods
void onChanged()
This method is called when the entire data set has changed, most likely through a call to  requery() on a  Cursor.
void onInvalidated()
This method is called when the entire data becomes invalid, most likely through a call to  deactivate() or  close() on a  Cursor.
那么 CursorAdapter 是如何实现对基于 uri 的数据库内容变化进行监听呢?
它当然是 借助Cursor 来实现的。
但是 CursorAdapterContentObserver相对应对外提供(可以重载)的接口是:
onContentChanged()
当时 CursorAdapterDataSetObserver相对应对外提供(可以重载)的接口是:
onChanged()->notifyDataSetChanged() //这个消息并完全不是从Cursor传递来,它会在CursorAdapter内手动被调用
onInvalidated()->notifyDataSetInvalidated() //这个消息并不是从Cursor传递来。
具体可以参照 附件2的android.widget.CursorAdapter源代码
CursorAdapternotifyDataSetChanged()notifyDataSetInvalidated()事件 可以 继续往外传递
BaseAdapter为此提供了以下系列方法。
void notifyDataSetChanged()
Notifies the attached observers that the underlying data has been changed and any View reflecting the data set should refresh itself.
void notifyDataSetInvalidated()
Notifies the attached observers that the underlying data is no longer valid or available.
void registerDataSetObserver( DataSetObserver observer)
Register an observer that is called when changes happen to the data used by this adapter.
void unregisterDataSetObserver( DataSetObserver observer)
Unregister an observer that has previously been registered with this adapter via  registerDataSetObserver(DataSetObserver).
android.widget.BaseAdapter的部分源代码如下:
public abstract class   BaseAdapter   implements  ListAdapter, SpinnerAdapter { 
private final  DataSetObservable mDataSetObservable = new DataSetObservable(); 
public boolean hasStableIds() { return false; } 
public void   registerDataSetObserver (DataSetObserver observer) { mDataSetObservable.registerObserver(observer); } 
public void  unregisterDataSetObserver (DataSetObserver observer) { mDataSetObservable.unregisterObserver(observer); } 
/** * Notifies the attached View that the underlying data has been changed * and it should refresh itself. */ 
public void  notifyDataSetChanged()  { mDataSetObservable.notifyChanged(); } 
public void  notifyDataSetInvalidated()  { mDataSetObservable.notifyInvalidated(); } 
-------------------省略------------------
注意:对于 BaseAdapter,外部可以强行调用 notifyDataSetChangednotifyDataSetInvalidated来通知DataSetObserver observer
AbstractCursor.java文件
/**
 * This is an abstract cursor class that handles a lot of the common code
 * that all cursors need to deal with and is provided for convenience reasons.
 */

public abstract class  AbstractCursor   implements  CrossProcessCursor {
    private static final String TAG = "Cursor";

    DataSetObservable mDataSetObservable = new DataSetObservable();
    ContentObservable mContentObservable = new ContentObservable();


 -------------------省略------------------
    
    public void deactivate() {
        deactivateInternal();
    }
    
    /**
     * @hide
     */

    public void  deactivateInternal()  {
        if (mSelfObserver != null) {
            mContentResolver.unregisterContentObserver(mSelfObserver);
            mSelfObserverRegistered = false;
        }
         mDataSetObservable.notifyInvalidated();
    }
    
    public boolean  requery()  {
        if (mSelfObserver != null && mSelfObserverRegistered == false) {
            mContentResolver.registerContentObserver(mNotifyUri, true, mSelfObserver);
            mSelfObserverRegistered = true;
        }
         mDataSetObservable.notifyChanged();
        return true;
    }

    public boolean isClosed() {
        return mClosed;
    }
    
    public void  close()  {
        mClosed = true;
        mContentObservable.unregisterAll();
         deactivateInternal();
    }

 -------------------省略------------------
    public void  registerContentObserver (ContentObserver observer) {
        mContentObservable.registerObserver(observer);
    }

    public void  unregisterContentObserver (ContentObserver observer) {
         // cursor will unregister all observers when it close
        if (!mClosed) {
            mContentObservable.unregisterObserver(observer);
        }
    }
    
    /**
     * This is hidden until the data set change model has been re-evaluated.
     * @hide
     */

    protected void  notifyDataSetChange () {
        mDataSetObservable.notifyChanged();
    }
    
    /**
     * This is hidden until the data set change model has been re-evaluated.
     * @hide
     */

    protected DataSetObservable getDataSetObservable() {
        return mDataSetObservable;
        
    }
    public void  registerDataSetObserver (DataSetObserver observer) {
         mDataSetObservable.registerObserver(observer);
        
    }

    public void  unregisterDataSetObserver (DataSetObserver observer) {
         mDataSetObservable.unregisterObserver(observer);
    }

    /**
     * Subclasses must call this method when they finish committing updates to notify all
     * observers.
     *
     * @param selfChange
     */

    protected void  onChange (boolean selfChange) {
        synchronized (mSelfObserverLock) {
             mContentObservable.dispatchChange(selfChange);
             if  (mNotifyUri != null &&  selfChange ) {
                 mContentResolver.notifyChange(mNotifyUri, mSelfObserver);
            }
        }
    }

    /**
     * Specifies a content URI to watch for changes.
     *
     * @param cr The content resolver from the caller's context.
     * @param notifyUri The URI to watch for changes. This can be a
     * specific row URI, or a base URI for a whole class of content.
     */

     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;
        }
    }
 -------------------省略------------------
    @Override
    protected void  finalize()  {
        if (mSelfObserver != null && mSelfObserverRegistered == true) {
            mContentResolver.unregisterContentObserver(mSelfObserver);
        }
    }

    /**
     * Cursors use this class to track changes others make to their URI.
     */

     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);
            }
        }
    }
 -------------------省略------------------
    protected ContentResolver  mContentResolver;
    protected boolean mClosed = false;
    private Uri mNotifyUri;
    private ContentObserver mSelfObserver;
    final private Object mSelfObserverLock = new Object();
    private boolean mSelfObserverRegistered;
}
public abstract class CursorAdapter extends BaseAdapter implements Filterable,
        CursorFilter.CursorFilterClient {
-------------------省略------------------
    protected ChangeObserver mChangeObserver;
    /**
     * This field should be made private, so it is hidden from the SDK.
     * {@hide}
     */

    protected DataSetObserver mDataSetObserver = new MyDataSetObserver();
    /**
     * This field should be made private, so it is hidden from the SDK.
     * {@hide}
     */

-------------------省略------------------
    public CursorAdapter(Context context, Cursor c) {
        init(context, c, true);
    }
-------------------省略------------------
    protected void init(Context context, Cursor c, boolean autoRequery) {
        boolean cursorPresent = c != null;
        mAutoRequery = autoRequery;
        mCursor = c;
        mDataValid = cursorPresent;
        mContext = context;
        mRowIDColumn = cursorPresent ? c.getColumnIndexOrThrow("_id") : -1;
        mChangeObserver = new ChangeObserver();
        if (cursorPresent) {
            c.registerContentObserver(mChangeObserver);
            c.registerDataSetObserver(mDataSetObserver);

        }
    }
-------------------省略------------------    
    /**
     * Change the underlying cursor to a new cursor. If there is an existing cursor it will be
     * closed.
     * 
     * @param cursor the new cursor to be used
     */

    public void changeCursor(Cursor cursor) {
        if (cursor == mCursor) {
            return;
        }
        if (mCursor != null) {
            mCursor.unregisterContentObserver(mChangeObserver);
            mCursor.unregisterDataSetObserver(mDataSetObserver);
            mCursor.close();

        }
        mCursor = cursor;
        if (cursor != null) {
            cursor.registerContentObserver(mChangeObserver);
            cursor.registerDataSetObserver(mDataSetObserver);

            mRowIDColumn = cursor.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();
        }
    }
-------------------省略------------------
    /**
     * Called when the {@link ContentObserver} on the cursor receives a change notification.
     * The default implementation provides the auto-requery logic, but may be overridden by
     * sub classes.
     * 
     * @see ContentObserver#onChange(boolean)
     */

    protected void onContentChanged() {
        if (mAutoRequery && mCursor != null && !mCursor.isClosed()) {
            if (Config.LOGV) Log.v("Cursor", "Auto requerying " + mCursor + " due to update");
            mDataValid = mCursor.requery();
        }
    }

    private class ChangeObserver extends ContentObserver {
        public 
ChangeObserver() {
            super(new Handler());
        }

       
 @Override
        public boolean deliverSelfNotifications() {
            return true;
        }

        @Override
        public void onChange(boolean selfChange) {
            onContentChanged();
        }
    }

    private class MyDataSetObserver extends DataSetObserver {
        @Override
        public void onChanged() {
            mDataValid = true;
            notifyDataSetChanged();
        }
        @Override
        public void onInvalidated() {
            mDataValid = false;
            notifyDataSetInvalidated();
        }
    }
}

你可能感兴趣的:(Android数据库内容变化的监听)