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()方法。
- 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对象的实现类AbstractCursor内部会实例化一个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),那么AbstractCursor类中的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两个对象。并且调用c.registerContentObserver(mChangeObserver),c.registerDataSetObserver(mDataSetObserver),这两个方法在Cursor中:
类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中有一套观察者模式,其中维护了两个主题,mContentObservable,mDataSetObservable。在这套观察者模式中CursorAdapter提供了两个观察者mChangeObserver,mDataSetObserver。当Cursor中的主题通知改变的时候,执行CursorAdapter中的两个观察者中的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(false)方法:
类: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提供的框架。我们可以在数据插入数据库之后,自动进行页面的刷新。
附:
- AdapterView与Adapter(三) --Cursor及CursorAdapter数据变化监听
- AdapterView与Adapter(二) --CursorAdapter
- AdapterView与Adapter(四) --App调试内存泄露之Cursor
- AdapterView与Adapter(一)
- CursorAdapter如何监听数据变化通知界面刷新
- AdapterView及Adapter分析
- AdapterView与Adapter(五) --AsyncQueryHandler
- AdapterView 与 Adapter
- Android cursor和cursorAdapter 的监听机制
- Data binding的使用(三)----监听数据的变化
- Android高级控件----AdapterView与Adapter详解(转)
- 安卓Adapter 与AdapterView笔记
- Android高级控件----AdapterView与Adapter
- Android高级控件----AdapterView与Adapter
- Android高级控件----AdapterView与Adapter详解
- Android高级控件----AdapterView与Adapter
- Android高级控件----AdapterView与Adapter
- Android高级控件----AdapterView与Adapter
- JavaScript高级程序设计【面向对象-继承】
- [iOS] 初探 iOS8 中的 Size Class
- TSM数据保留策略中的几个难理解的概念
- 黑马程序员——多线程
- Reverse Integer
- AdapterView与Adapter(三) --Cursor及CursorAdapter数据变化监听
- DOS命令大全:Net use命令详解
- 使用Qt linguist进行多语言界面设计
- 做个友好的链接
- html5 绘制类似墙型的背景
- Android ProgressDialog 控件自定义(Loading)
- 由浅入深探究 MySQL索引结构原理、性能分析与优化
- 第一次使用框架-amaze UI
- POJ 3684 Physics Experiment(弹性碰撞)