美文网首页Android那些事儿程序员今日看点
Cursor和CursorAdapter中的观察者模式机制

Cursor和CursorAdapter中的观察者模式机制

作者: Android那些事儿 | 来源:发表于2016-11-26 12:03 被阅读116次

    文章摘要:
    1、观察者模式构建松耦合的架构,Cursor和CursorAdapter就是其中一个例子,Cursor,CursorAdapter配合ListView一起使用,当数据发生改变的时候,可以实现列表数据自动刷新,不再需要手动执行Cursor.requery。
    2、CursorAdapter与Cursor之间通过观察者之间建立关系。Cursor是主题,CursorAdapter是观察者。
    ContentProvider与Cursor之间通过Uri之间建立观察者模式,ContentProvider是主题,Cursor是观察者。


    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)监听。

    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方法。在这里我们的SelfObserver是观察者。
    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),让这两个ContentResolver与Cursor对象建立了联系。这两个方法在Cursor中:
    类****Cursor.java

    public void registerContentObserver(ContentObserver observer) {  
            mContentObservable.registerObserver(observer);  
    }  
    public void registerDataSetObserver(DataSetObserver observer) {  
            mDataSetObservable.registerObserver(observer);  
    }
    

    这里涉及到两个主题类,mContentObservable与mDataSetObservable都继承自Observable,主题类有如下几大功能,将观察者对象加入到列表,收到变化时,遍历列表通知观察者。执行观察者对象的onChange方法。

    总结:关于CursorAdapter与Cursor的关系,我们可以概括一下,Cursor中有一套观察者模式,其中维护了两个主题,mContentObservable,mDataSetObservable。在这套观察者模式中CursorAdapter提供了两个观察者对象mChangeObserver,mDataSetObserver。当Cursor中的主题通知改变的时候,会触发执行CursorAdapter中的两个观察者中的onChanged方法。

    4、CursorAdapter和Cursor以及ContentProvider之间的关系

    CursorAdapter与Cursor之间通过观察者之间建立关系。Cursor是主题,CursorAdapter是观察者。
    ContentProvider与Cursor之间通过Uri之间建立观察者模式,ContentProvider是主题,Cursor是观察者。

    5、ContentProvider主题发布通知,Cursor观察者的逻辑。

    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中的业务逻辑:
    类: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);  
                    }  
                }  
     }
    

    总结:CursorProvider主题发送通知,身为观察者的Cursor收到变化并执行自身的onChange方法。但Cursor也是主题,其收到变化,会通知其所有的观察者对象,也就是CursorAdapter。
    6、CursorAdapter中观察者的逻辑。

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

    相关文章

      网友评论

        本文标题:Cursor和CursorAdapter中的观察者模式机制

        本文链接:https://www.haomeiwen.com/subject/ixtgpttx.html