• Cursor,CursorAdapter中的观察者模式解析


    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 提供的框架。我们可以在数据插入数据库之后,自动进行页面的刷新。

    附:

     
  • 相关阅读:
    印度出差之一
    印度出差疯狂的鸡翅
    GET和POST两种基本请求方法的区别
    对sleep和wait的理解
    Jquery 鼠标滑过时改变元素透明度的动画效果
    记忆里的科比
    New Features Summary Of Sybase® PowerDesigner® 15.0 For Windows[PD15新功能特征摘要]
    WF工作流接口规范
    Foxmail安装文件夹的整体转移(收集)
    c# vs2005 多线程中调用窗体控件 (摘)
  • 原文地址:https://www.cnblogs.com/xiaoxiaoshen/p/5199922.html
Copyright © 2020-2023  润新知