Android数据库内容变化的监听

古人已用三冬足,年少今开万卷余。这篇文章主要讲述Android数据库内容变化的监听相关的知识,希望能为你提供帮助。
首先介绍内容监测的基本模式
基于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"只是说如果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相关的内容监听,可以调用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来实现的。
但是CursorAdapter与ContentObserver相对应对外提供(可以重载)的接口是:
onContentChanged()
当时CursorAdapter与DataSetObserver相对应对外提供(可以重载)的接口是:
onChanged()-> notifyDataSetChanged()//这个消息并完全不是从Cursor传递来,它会在CursorAdapter内手动被调用
onInvalidated()-> notifyDataSetInvalidated()//这个消息并不是从Cursor传递来。
具体可以参照附件2的android.widget.CursorAdapter源代码
CursorAdapter的notifyDataSetChanged()和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,外部可以强行调用notifyDataSetChanged和notifyDataSetInvalidated来通知DataSetObserver observer【Android数据库内容变化的监听】再分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://www.cnblogs.com/captainbed


































































































































































    推荐阅读