AdapterView与Adapter(三) --Cursor及CursorAdapter数据变化监听

来源:互联网 发布:手机卡盟源码 编辑:程序博客网 时间:2024/05/22 04:28

第一弹

本文部分参考 http://www.cnblogs.com/ufocdy/archive/2011/03/17/1987327.html 

主要是以简单的语言说明cursor和cursorAdapter的监听机制

先来讲讲cursor的监听机制,

给cursor加监听很简单,调用cursor.registerContentOberserver()即可,然后重写onChange()方法,这样数据库变化,就会回调onChange方法

背后的监听机制是什么呢?

cursor是接口,实现应该是在AbstractCursor里面,AbstractCursor有一个ContentObservable继承自Observable,这个就是经典的观察者模式了,

调用这个方法后,会向这里注册一个观察者,来监控数据库

现在有观察者了,那数据库变化,又是怎么通知过来的呢?

还记得自定义provider的时候,有一句必须要加的话不?在add和update和delete的时候--->cur.setNotificationUri(getContext().getContentResolver(), uri);

这里就是通知observer数据库变化的,其实是通知AbstractCursor的setNotificationUri

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;
        }
    }

然后上面我们不是刚好通过cursor在这个AbstractCursor中加入了观察者么?原来世界如此美好,数据库的变化一切尽在监控之中

再来说说cursorAdapter的监听

cursorAdapter自己内部已经做好了监听,你想在数据库变化后做一些改变,只要重写onContentChanged()即可

那么它是如何监听的呢?

其实他的机制和上面的cursor是一样,在你调用cusoradapeter.changeCursor方法的时候,系统会调用一个cursorAdapter.registerContentObserver和registerDatasetObserver,同时取消上次注册的监听

然后呢?然后就没有然后了,你坐等数据库变化就可以了.


第二弹

情景分析:

我们有一个Service,这个Service在后台会不断的更新多条数据,我们又想将不断更新的数据展现在ui上面这时你是怎么解决的呢?其实就是类似有些浏览器的下载管理器界面,有没有想过是怎么实现的??

解决方案:

1,使用通知,只能在通知栏看到更新,加入用户想在一个activity中有个进度显示呢?

2,发送更新广播,当是在一个listView中的多个列需要更新广播就有点吃力了;

还有吗?

参考方案:

利用Provider将数据持久化,再用Cursor监听Provider的变化来更新数据。当然这需要中Service update数据。

-----部分代码-------

//一个观察者

privateclass MyContentObserver extends ContentObserver {

 

public MyContentObserver() {

super(new Handler());

}

 

@Override

publicvoid onChange(boolean selfChange) {

super.onChange(selfChange);

Log.i("DLA","MyContentObserver onChange!");

//处理数据更新回调

refreshData();

}

 

}

 

privatevoid refreshData() {

if (mCursor.isClosed()) {

return;

}

//更新

mCursor.requery();

}

 

//一个实现CursorAdapter的适配器

private MyAdaptermAdapter;

 

private CursormCursor;

 

private MyContentObservermObserver;

 

@Override

protectedvoid onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.list);

setupViews();

mCursor = getContentResolver().query(MyProvider.CONTENT_URI,sAppReadableColumnsArray,

null,null, null);

mObserver =new MyContentObserver();

//注册观察者

mCursor.registerContentObserver(mObserver);

mAdapter =new MyAdapter(this, R.layout.list_item,mCursor);

setListAdapter(mAdapter);

}

 

@Override

protectedvoid onDestroy() {

super.onDestroy();

if (mCursor !=null) {

mCursor.unregisterContentObserver(mObserver);

mCursor.close();

}

}

⋯⋯

⋯⋯

这样实现后当MyProvider.CONTENT_URI对应的数据发生变化时都会调用观察者的onChange方法,mCursor.requery()执行后listview就直接更新了。(不知道在其他类型的Adapter中是否自动更新,而不需要调用adapter的notifyDataSetChanged)


第三弹


Cursor,CursorAdapter配合ListView一起使用,当数据发生改变的时候,可以实现列表数据自动刷新。现在介绍一下内中原理。

 

1、ContentProvider与Cursor之间的关系。

我们使用Uri向ContentProvider发起一个query请求用来得到Cursor对象。但在cursor对象返回之前,我们会给cursor对象执行setNotificationUri()方法。

[java]
  1. public Cursor query(Uri uri,String[] projection,String selection,String[] selectionArgs,String sortOrder){  
  2.           
  3.         SQLiteDatabase db = mOpenHelper.getReadableDatabase();  
  4.           
  5.         Cursor cursor = null;  
  6.         switch(URI_MATCHER.match(uri)){  
  7.         case XXX:  
  8.             break;  
  9.         case XXX:  
  10.             break;  
  11.             ..  
  12.             default:  
  13.                 break;  
  14.         }  
  15.         if(cursor != null){  
  16.             cursor.setNotificationUri(getContext().getContentResolver(), XXX.CONTENT_URI);  
  17.         }  
  18.         return cursor;  
  19.     }  

在setNotificationUri方法中执行内容如下:

类:AbstractCursor.java

[java]
  1. public void setNotificationUri(ContentResolver cr, Uri notifyUri) {  
  2.         synchronized (mSelfObserverLock) {  
  3.             mNotifyUri = notifyUri;  
  4.             mContentResolver = cr;  
  5.             if (mSelfObserver != null) {  
  6.                 mContentResolver.unregisterContentObserver(mSelfObserver);  
  7.             }  
  8.             mSelfObserver = new SelfContentObserver(this);  
  9.             mContentResolver.registerContentObserver(mNotifyUri, true, mSelfObserver);  
  10.             mSelfObserverRegistered = true;  
  11.         }  
  12.     }  

在这个方法内部,首先检查mSelfObserver是否为null,如果不为null,解除mSelfObserver对uri的监听。然后重新使用new进行实例化一个mSelfObserver对象,mSelfObserver继承自ContentObserver。再然后给mSelfObserver注册Uri(mNotifyUri)监听。

类:SelfContentServer.java

[java]
  1. protected static class SelfContentObserver extends ContentObserver {  
  2.         WeakReference<AbstractCursor> mCursor;  
  3.   
  4.         public SelfContentObserver(AbstractCursor cursor) {  
  5.             super(null);  
  6.             mCursor = new WeakReference<AbstractCursor>(cursor);  
  7.         }  
  8.   
  9.         @Override  
  10.         public boolean deliverSelfNotifications() {  
  11.             return false;  
  12.         }  
  13.   
  14.         @Override  
  15.         public void onChange(boolean selfChange) {  
  16.             AbstractCursor cursor = mCursor.get();  
  17.             if (cursor != null) {  
  18.                 cursor.onChange(false);  
  19.             }  
  20.         }  
  21.     }  

总结一下:在query发起者得到了一个Cursor对象,并且这个Cursor对象的实现类AbstractCursor内部会实例化一个mSelfObserver对象注册Uri的监听。根据观察者模式逻辑,当uri执行notify方法时,我们的mSelfObserver会收到通知并且执行onChange方法。

2、通知Cursor中mSelfObserver,Uri数据发生改变。

在我们的ContentProvider中的update以及insert或者delete方法中,我们在方法执行的最后按照我们的需求,我们会执行如下方法调用(以update方法为例):

[java]
  1. public int update(Uri uri,ContentValues values,String selection,String[] selectionArgs){  
  2.         SQLiteDatabase db = mOpenHelper.getWritableDatabase();  
  3.         int affectedRows = 0;  
  4.         switch(URI_MATCHER.match(uri)){  
  5.         case XXX:  
  6.             break;  
  7.         case XXX:  
  8.             break;  
  9.             ...  
  10.             default:  
  11.                 break;  
  12.         }  
  13.           
  14.         if(affectedRows > 0){  
  15.             getContext().getContentResolver().notifyChange(XXX.CONTENT_URI,null);  
  16.         }  
  17.         return affectedRows;  
  18.     }  

当我们执行方getContext().getContentResolver().notifyChange(XXX.CONTENT_URI,null),那么AbstractCursor类中的mSelfObserver就会收到通知并且回调onChange方法。至于在onChange方法中做了那些工作,我们稍后介绍,我们先来看一下cursor和cursorAdapter之间的关系。

3、Cursor和CursorAdapter之间的关系。

当我们构建CursorAdapter时,我们会将cursor对象作为CursorAdapter的构造参数传递到CursorAdapter中。

类:CursorAdapter.java

[java]
  1. public CursorAdapter(Context context, Cursor c, int flags) {  
  2.         init(context, c, flags);  
  3. }  
  4.   
  5. void init(Context context, Cursor c, int flags) {  
  6.         if ((flags & FLAG_AUTO_REQUERY) == FLAG_AUTO_REQUERY) {  
  7.             flags |= FLAG_REGISTER_CONTENT_OBSERVER;  
  8.             mAutoRequery = true;  
  9.         } else {  
  10.             mAutoRequery = false;  
  11.         }  
  12.         boolean cursorPresent = c != null;  
  13.         mCursor = c;  
  14.         mDataValid = cursorPresent;  
  15.         mContext = context;  
  16.         mRowIDColumn = cursorPresent ? c.getColumnIndexOrThrow("_id") : -1;  
  17.         if ((flags & FLAG_REGISTER_CONTENT_OBSERVER) == FLAG_REGISTER_CONTENT_OBSERVER) {  
  18.             mChangeObserver = new ChangeObserver();  
  19.             mDataSetObserver = new MyDataSetObserver();  
  20.         } else {  
  21.             mChangeObserver = null;  
  22.             mDataSetObserver = null;  
  23.         }  
  24.   
  25.         if (cursorPresent) {  
  26.             if (mChangeObserver != null)          
  27.                     c.registerContentObserver(mChangeObserver);  
  28.             if (mDataSetObserver != null)   
  29.                     c.registerDataSetObserver(mDataSetObserver);  
  30.         }  
  31.     }  

总结:CursorAdapter通过new关键字初始化了mChangeObserver,mDataSetObserver两个对象。并且调用c.registerContentObserver(mChangeObserver),c.registerDataSetObserver(mDataSetObserver),这两个方法在Cursor中:

类Cursor.java

[java]
  1. public void registerContentObserver(ContentObserver observer) {  
  2.         mContentObservable.registerObserver(observer);  
  3. }  
  4. public void registerDataSetObserver(DataSetObserver observer) {  
  5.         mDataSetObservable.registerObserver(observer);  
  6. }  

mContentObservable是ContentObservable的实例化对象。在这个类中:

类:ContentObservable.java

[java]
  1. public class ContentObservable extends Observable<ContentObserver> {  
  2.   
  3.     @Override  
  4.     public void registerObserver(ContentObserver observer) {  
  5.         super.registerObserver(observer);  
  6.     }  
  7.   
  8.     public void dispatchChange(boolean selfChange) {  
  9.         synchronized(mObservers) {  
  10.             for (ContentObserver observer : mObservers) {  
  11.                 if (!selfChange || observer.deliverSelfNotifications()) {  
  12.                     observer.dispatchChange(selfChange);  
  13.                 }  
  14.             }  
  15.         }  
  16.     }  
  17.   
  18.     public void notifyChange(boolean selfChange) {  
  19.         synchronized(mObservers) {  
  20.             for (ContentObserver observer : mObservers) {  
  21.                 observer.onChange(selfChange);  
  22.             }  
  23.         }  
  24.     }  
  25. }  

我们看到ContentObservable继承自Observable,典型的观察者模式,这个类是主题类。registerObserver方法会将ContentObserver加入到列表中,当收到通知会执行notifyChange方法,在这个方法内,所有的ContentObserver会执行onChange方法。

mDataSetObservable是DataSetObservable的实例化对象,在这个类中:
类:DataSetObservable.java

[java]
  1. public class DataSetObservable extends Observable<DataSetObserver> {  
  2.   
  3.     public void notifyChanged() {  
  4.         synchronized(mObservers) {  
  5.             for (int i = mObservers.size() - 1; i >= 0; i--) {  
  6.                 mObservers.get(i).onChanged();  
  7.             }  
  8.         }  
  9.     }  
  10.   
  11.     public void notifyInvalidated() {  
  12.         synchronized (mObservers) {  
  13.             for (int i = mObservers.size() - 1; i >= 0; i--) {  
  14.                 mObservers.get(i).onInvalidated();  
  15.             }  
  16.         }  
  17.     }  
  18. }  

同样也是继承自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接到通知),业务逻辑。

[java]
  1. protected static class SelfContentObserver extends ContentObserver {  
  2.         WeakReference<AbstractCursor> mCursor;  
  3.   
  4.         public SelfContentObserver(AbstractCursor cursor) {  
  5.             super(null);  
  6.             mCursor = new WeakReference<AbstractCursor>(cursor);  
  7.         }  
  8.   
  9.         @Override  
  10.         public boolean deliverSelfNotifications() {  
  11.             return false;  
  12.         }  
  13.   
  14.         @Override  
  15.         public void onChange(boolean selfChange) {  
  16.             AbstractCursor cursor = mCursor.get();  
  17.             if (cursor != null) {  
  18.                 cursor.onChange(false);  
  19.             }  
  20.         }  
  21.     }  

会执行cursor.onChange(false);

我们看一下在onChange中的业务逻辑:

类:AbstractCursor.java

[java]
  1. protected void onChange(boolean selfChange) {  
  2.         synchronized (mSelfObserverLock) {  
  3.             mContentObservable.dispatchChange(selfChange);  
  4.             if (mNotifyUri != null && selfChange) {  
  5.                 mContentResolver.notifyChange(mNotifyUri, mSelfObserver);  
  6.             }  
  7.         }  
  8. }  

执行mContentObservable.dispatchChange(false)方法,通过3中可知,执行逻辑如下:

类ContentObservable.java

[java]
  1. public void dispatchChange(boolean selfChange) {  
  2.         synchronized(mObservers) {  
  3.             for (ContentObserver observer : mObservers) {  
  4.                 if (!selfChange || observer.deliverSelfNotifications()) {  
  5.                     observer.dispatchChange(selfChange);  
  6.                 }  
  7.             }  
  8.  }  

会执行所有注册的观察者的dispatchChange(false)方法;

在dispatchChange(false)中的业务逻辑:

 

6,在5、中触发的观察者在dispatchChange(false)方法时的业务逻辑

首先会执行ChangeObserver的父类ContentObserver的dispatchChange(false)方法:

类:ContentObserver.java

[java]
  1. public final void dispatchChange(boolean selfChange) {  
  2.         if (mHandler == null) {  
  3.             onChange(selfChange);  
  4.         } else {  
  5.             mHandler.post(new NotificationRunnable(selfChange));  
  6.         }  
  7. }  

我们看到会执行onChange(false);

类CursorAdapter$ChangeObserver.java

[java]
  1. private class ChangeObserver extends ContentObserver {  
  2.         public ChangeObserver() {  
  3.             super(new Handler());  
  4.         }  
  5.   
  6.         @Override  
  7.         public boolean deliverSelfNotifications() {  
  8.             return true;  
  9.         }  
  10.   
  11.         @Override  
  12.         public void onChange(boolean selfChange) {  
  13.             onContentChanged();  
  14.         }  
  15. }  

然后会执行onContentChanged()方法;

[java]
  1. protected void onContentChanged() {  
  2.         if (mAutoRequery && mCursor != null && !mCursor.isClosed()) {  
  3.             mDataValid = mCursor.requery();  
  4.         }  
  5. }  

在这里我们找到了我们的答案,mCursor.requery(),会重新刷新并填充mCursor对象。

然后还没有结束:

我们的cursor重新填充了,但是不会告诉Adapter执行notifyDataSetChanged()方法,因为只有执行了这个方法,我们的界面才会刷新。

7、通知Adapter执行notifyDataSetChanged()方法。

当我们的Cursor执行requery方法的时候,我们看一下业务逻辑:

类:AbstractCursor.java

 

[java]
  1. public boolean requery() {  
  2.         if (mSelfObserver != null && mSelfObserverRegistered == false) {  
  3.             mContentResolver.registerContentObserver(mNotifyUri, true, mSelfObserver);  
  4.             mSelfObserverRegistered = true;  
  5.         }  
  6.         mDataSetObservable.notifyChanged();  
  7.         return true;  
  8. }  

我们看到我们最后一位主角登场了,他就是mDataSetObservable,通过3、可知,这是个主题,当它notifyChanged的时候,它的所有的观察者会执行onChanged方法。

 

我们看一下观察者的业务逻辑:

类:CursorAdapter$MyDataSetObserver.java

[java]
  1. private class MyDataSetObserver extends DataSetObserver {  
  2.         @Override  
  3.         public void onChanged() {  
  4.             mDataValid = true;  
  5.             notifyDataSetChanged();  
  6.         }  
  7.   
  8.         @Override  
  9.         public void onInvalidated() {  
  10.             mDataValid = false;  
  11.             notifyDataSetInvalidated();  
  12.         }  
  13. }  

在onChanged方法中,我们看到了我们的答案,notifySetChanged();

 

总结:我们在使用Cursor,CursorAdapter搭配ListView进行上层业务开发的过程中,我们只要合理的利用android提供的框架。我们可以在数据插入数据库之后,自动进行页面的刷新。

附:

\






1 0