Cursor , CursorAdapter 配合 ListView 一起使用,当数据发生改变的时候,可以实现列表数据自动刷新。现在介绍一下内中原理。
1 、 ContentProvider 与 Cursor 之间的关系。
我们使用 Uri 向 ContentProvider 发起一个 query 请求用来得到 Cursor 对象。但在 cursor 对象返回之前,我们会给 cursor 对象执行 setNotificationUri ()方法。
publicCursorquery(Uriuri,String[] projection,String selection,String[]selectionArgs,String sortOrder){
SQLiteDatabasedb = mOpenHelper.getReadableDatabase();
Cursorcursor = null;
switch(URI_MATCHER.match(uri)){
caseXXX:
break;
caseXXX:
break;
..
default:
break;
}
if(cursor!= null){
cursor.setNotificationUri(getContext().getContentResolver(),XXX.CONTENT_URI);
}
returncursor;
}
在 setNotificationUri 方法中执行内容如下:
类: AbstractCursor.java
publicvoidsetNotificationUri(ContentResolver cr, Uri notifyUri) {
synchronized(mSelfObserverLock){
mNotifyUri= notifyUri;
mContentResolver= cr;
if(mSelfObserver!= null){
mContentResolver.unregisterContentObserver(mSelfObserver);
}
mSelfObserver= newSelfContentObserver(this);
mContentResolver.registerContentObserver(mNotifyUri,true,mSelfObserver);
mSelfObserverRegistered= true;
}
}
在这个方法内部,首先检查 mSelfObserver 是否为 null ,如果不为 null, 解除mSelfObserver 对 uri 的监听。然后重新使用 new 进行实例化一个 mSelfObserver 对象, mSelfObserver 继承自 ContentObserver 。再然后给 mSelfObserver 注册 Uri( mNotifyUri )监听。
类: SelfContentServer.java
protectedstaticclassSelfContentObserver extendsContentObserver {
WeakReference<AbstractCursor>mCursor;
publicSelfContentObserver(AbstractCursor cursor) {
super(null);
mCursor= newWeakReference<AbstractCursor>(cursor);
}
@Override
publicbooleandeliverSelfNotifications() {
returnfalse;
}
@Override
publicvoidonChange(booleanselfChange) {
AbstractCursorcursor = mCursor.get();
if(cursor != null){
cursor.onChange(false);
}
}
}
总结一下:在 query 发起者得到了一个 Cursor 对象,并且这个 Cursor 对象的实现类 AbstractCursor 内部会实例化一个 mSelfObserver 对象注册 Uri 的监听。根据观察者模式逻辑,当 uri 执行 notify 方法时,我们的 mSelfObserver 会收到通知并且执行 onChange 方法。
2 、通知 Cursor 中 mSelfObserver , Uri 数据发生改变。
在我们的 ContentProvider 中的 update 以及 insert 或者 delete 方法中,我们在方法执行的最后按照我们的需求,我们会执行如下方法调用(以 update 方法为例):
publicintupdate(Uriuri,ContentValuesvalues,String selection,String[] selectionArgs){
SQLiteDatabasedb = mOpenHelper.getWritableDatabase();
intaffectedRows = 0;
switch(URI_MATCHER.match(uri)){
caseXXX:
break;
caseXXX:
break;
...
default:
break;
}
if(affectedRows> 0){
getContext().getContentResolver().notifyChange(XXX.CONTENT_URI,null);
}
returnaffectedRows;
}
当我们执行方 getContext ().getContentResolver().notifyChange( XXX.CONTENT_URI, null ) ,那么 AbstractCursor 类中的 mSelfObserver 就会收到通知并且回调 onChange 方法。至于在 onChange 方法中做了那些工作,我们稍后介绍,我们先来看一下 cursor 和 cursorAdapter 之间的关系。
3 、 Cursor 和 CursorAdapter 之间的关系。
当我们构建 CursorAdapter 时,我们会将 cursor 对象作为 CursorAdapter 的构造参数传递到 CursorAdapter 中。
类: CursorAdapter.java
publicCursorAdapter(Context context, Cursor c, intflags) {
init(context,c, flags);
}
voidinit(Context context, Cursor c, intflags) {
if((flags & FLAG_AUTO_REQUERY)== FLAG_AUTO_REQUERY){
flags |=FLAG_REGISTER_CONTENT_OBSERVER;
mAutoRequery= true;
} else{
mAutoRequery= false;
}
booleancursorPresent = 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 两个对象。并且调用 c.registerContentObserver(mChangeObserver ) , c.registerDataSetObserver( mDataSetObserver ) ,这两个方法在 Cursor 中:
类 Cursor.java
publicvoidregisterContentObserver(ContentObserver observer) { mContentObservable.registerObserver(observer); } publicvoidregisterDataSetObserver(DataSetObserver observer) { mDataSetObservable.registerObserver(observer); }mContentObservable 是 ContentObservable 的实例化对象。在这个类中:
类: ContentObservable.java
publicclassContentObservable extendsObservable<ContentObserver> {
@Override
publicvoid registerObserver(ContentObserver observer) {
super.registerObserver(observer);
}
publicvoiddispatchChange(booleanselfChange) {
synchronized(mObservers){
for(ContentObserver observer : mObservers){
if(!selfChange || observer.deliverSelfNotifications()) {
observer.dispatchChange(selfChange);
}
}
}
}
publicvoid notifyChange(boolean selfChange) {
synchronized(mObservers){
for(ContentObserver observer : mObservers) {
observer.onChange(selfChange);
}
}
}
}
我们看到 ContentObservable 继承自 Observable ,典型的观察者模式,这个类是主题类。 registerObserver 方法会将 ContentObserver 加入到列表中,当收到通知会执行 notifyChange 方法,在这个方法内,所有的 ContentObserver 会执行onChange 方法。
mDataSetObservable 是 DataSetObservable 的实例化对象,在这个类中: 类:DataSetObservable.java
publicclassDataSetObservable extendsObservable<DataSetObserver> {
publicvoidnotifyChanged() {
synchronized(mObservers){
for(inti = mObservers.size()- 1; i >= 0; i--) {
mObservers.get(i).onChanged();
}
}
}
publicvoidnotifyInvalidated() {
synchronized(mObservers){
for(inti = mObservers.size()- 1; i >= 0; i--) {
mObservers.get(i).onInvalidated();
}
}
}
}
同样也是继承自 Observer ,同样也是作为观察者中的主题,可以通知注册对象发生变化,执行对象的 onChanged 方法。
总结:关于 CursorAdapter 与 Cursor 的关系,我们可以概括一下, Cursor 中有一套观察者模式,其中维护了两个主题, mContentObservable ,mDataSetObservable 。在这套观察者模式中 CursorAdapter 提供了两个观察者mChangeObserver , mDataSetObserver 。当 Cursor 中的主题通知改变的时候,执行 CursorAdapter 中的两个观察者中的 onChanged 方法。
4 、 CursorAdapter 和 Cursor 以及 ContentProvider 之间的关系
CursorAdapter 与 Cursor 之间通过观察者之间建立关系。
ContentProvider 与 Cursor 之间通过 Uri 之间建立关系。
5 、当 Cursor 监听的 uri 发生了改变(即 Cursor 中的 mSelfObserver 接到通知),业务逻辑。
protectedstaticclassSelfContentObserver extendsContentObserver {
WeakReference<AbstractCursor>mCursor;
publicSelfContentObserver(AbstractCursor cursor) {
super(null);
mCursor= newWeakReference<AbstractCursor>(cursor);
}
@Override
publicbooleandeliverSelfNotifications() {
returnfalse;
}
@Override
publicvoid onChange(boolean selfChange) {
AbstractCursorcursor = mCursor.get();
if(cursor != null) {
cursor.onChange(false);
}
}
}
会执行 cursor.onChange(false);
我们看一下在 onChange 中的业务逻辑:
类: AbstractCursor.java
protectedvoidonChange(booleanselfChange) {
synchronized(mSelfObserverLock){
mContentObservable.dispatchChange(selfChange);
if(mNotifyUri != null && selfChange) {
mContentResolver.notifyChange(mNotifyUri,mSelfObserver);
}
}
}
执行 mContentObservable.dispatchChange(false) 方法,通过 3 中可知,执行逻辑如下:
类 ContentObservable.java
publicvoiddispatchChange(booleanselfChange) {
synchronized(mObservers){
for(ContentObserver observer : mObservers){
if(!selfChange || observer.deliverSelfNotifications()) {
observer.dispatchChange(selfChange);
}
}
}
会执行所有注册的观察者的 dispatchChange(false) 方法 ;
在 dispatchChange ( false )中的业务逻辑:
6, 在 5 、中触发的观察者在 dispatchChange ( false )方法时的业务逻辑
首先会执行 ChangeObserver 的父类 ContentObserver 的 dispatchChange (false )方法:
类: ContentObserver.java
publicfinalvoiddispatchChange(booleanselfChange) {
if(mHandler== null){
onChange(selfChange);
} else{
mHandler.post(newNotificationRunnable(selfChange));
}
}
我们看到会执行 onChange ( false );
类 CursorAdapter$ChangeObserver.java
privateclassChangeObserver extendsContentObserver {
publicChangeObserver() {
super(newHandler());
}
@Override
publicbooleandeliverSelfNotifications() {
returntrue;
}
@Override
publicvoidonChange(booleanselfChange) {
onContentChanged();
}
}
然后会执行 onContentChanged() 方法;
protectedvoidonContentChanged() {
if(mAutoRequery&& mCursor!= null&& !mCursor.isClosed()){
mDataValid= mCursor.requery();
}
}
在这里我们找到了我们的答案, mCursor.requery(), 会重新刷新并填充 mCursor对象。
然后还没有结束:
我们的 cursor 重新填充了,但是不会告诉 Adapter 执行 notifyDataSetChanged()方法,因为只有执行了这个方法,我们的界面才会刷新。
7 、通知 Adapter 执行 notifyDataSetChanged() 方法。
当我们的 Cursor 执行 requery 方法的时候,我们看一下业务逻辑:
类: AbstractCursor.java
publicbooleanrequery() {
if(mSelfObserver!= null&& mSelfObserverRegistered== false){
mContentResolver.registerContentObserver(mNotifyUri,true,mSelfObserver);
mSelfObserverRegistered= true;
}
mDataSetObservable.notifyChanged();
returntrue;
}
我们看到我们最后一位主角登场了,他就是 mDataSetObservable ,通过 3 、可知,这是个主题,当它 notifyChanged 的时候,它的所有的观察者会执行 onChanged方法。
我们看一下观察者的业务逻辑:
类: CursorAdapter$MyDataSetObserver.java
privateclassMyDataSetObserver extendsDataSetObserver {
@Override
publicvoidonChanged() {
mDataValid= true;
notifyDataSetChanged();
}
@Override
publicvoidonInvalidated() {
mDataValid= false;
notifyDataSetInvalidated();
}
}
在 onChanged 方法中,我们看到了我们的答案, notifySetChanged ();
总结:我们在使用 Cursor , CursorAdapter 搭配 ListView 进行上层业务开发的过程中,我们只要合理的利用 android 提供的框架。我们可以在数据插入数据库之后,自动进行页面的刷新。
附: