• ContentProvider和Cursor以及CursorAdapter三者之间内部链接实现原理 解析


        最近 在学习Android3.0中推出的 Loader 机制,其中CursorLoader 这个加载器说是可以实时监测数据和更新数据,为了一探究竟,就连带的将 ContentProvider和Cursor以及CursorAdapter三者间的内部交互分析了下,然而本章内容主要就是将这一块,至于Loader机制准备,下一篇来具体分析。

        对于这三个类我们知道,Contentprovider就是一个Android中进程间的内容共享机制,我们可以使用ContentResolver这个工具嫁接 目标 URI 来访问对应的Contentprovider,从而获取目标Cursor数据,Android中 使用Sqliet就是这样一个机制。然而在这三个类之间其实存在了两处的观测者模式的运用。第一处在于Cursor  和 Contentprovider 之间,第二处在于 Cursor 和 CursorAdapter 之间,下面我们先来看一张时序图大致的了解下。Ps: 时序图 有哪里不对的还请及时指出啊。

                    

       上面说到观察者模式的运用 第一处在于Cursor  和 Contentprovider 之间,我们可以通过上面的时序图来加以分析,当我们通过 ContentResolver 对目标ContentProvider的数据进行CRUD(增删改查)操作时,在返回目标Cursor数据之前,我们发现在每个CRUD操作中有一个setNotifycationUri()这个方法,那么这个方法里到底做了什么呢,我们可以看看。

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

    我们可以发现,这里它创建了一个SelfContentObserver的对象并且给它注册了Uri监听。这里SelfContentObserver看起源码知道了它继承了ContentObserver,就是一个Observer,这样一来当Uri变动时,我们就可以通知它了。注意了在我们进行CRUD操作时,我们经常会加一句 :getContext().getContentResolver().notifyChange(XXX.CONTENT_URI,null),那么这样一来Cursor类中的mSelfObserver就会收到通知并且回调onChange方法,到这里我们是不是可以看出来了这就是观察者模式的运用呢。

        至于第二处则在于 Cursor 和 CursorAdapter 之间,同样的 我们也可从上面的时序图中发现。CursorAdapter中持有两个观察者:mChangeObserver和mDataSetObserver.这两个Observer在 CursorAdapter初始化时或者调用其changeCursor(Cursor c)或swapCursor(Cursor c)方法时,就被注册到Cursor中了,三种方式的代码依次如下:

     void init(Context context, Cursor c, int flags) {
           ...省略
            mCursor = c;
             ...省略
            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);
            }
        }
      public void changeCursor(Cursor cursor) {
            Cursor old = swapCursor(cursor);
            if (old != null) {
                old.close();
            }
        }
     public Cursor swapCursor(Cursor newCursor) {
            if (newCursor == mCursor) {
                return null;
            }
            Cursor oldCursor = mCursor;
            if (oldCursor != null) {
                if (mChangeObserver != null) oldCursor.unregisterContentObserver(mChangeObserver);
                if (mDataSetObserver != null) oldCursor.unregisterDataSetObserver(mDataSetObserver);
            }
            mCursor = newCursor;
            if (newCursor != null) {
                if (mChangeObserver != null) newCursor.registerContentObserver(mChangeObserver);
                if (mDataSetObserver != null) newCursor.registerDataSetObserver(mDataSetObserver);
                mRowIDColumn = newCursor.getColumnIndexOrThrow("_id");
                mDataValid = true;
                // notify the observers about the new cursor
                notifyDataSetChanged();
            } else {
                mRowIDColumn = -1;
                mDataValid = false;
                // notify the observers about the lack of a data set
                notifyDataSetInvalidated();
            }
            return oldCursor;
        }

    我们可以看到,这两个Observer在初始化Adapter的时候被创建,而后会在不同情况下注册到Cursor中。这里是因为Cursor中持有两个目标对象:mContentObservable和mDataSetObservable 这两个类就继承了Observable接口。所以其实是它们两分别接受了Observer的注册。代码如下:

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

    到这里第二处观察者模式运用就显示出来啦!

        从时序图中,我们可以看到当Cursor类中的mSelfObserver收到通知后就会调用onChange方法

    protected void onChange(boolean selfChange) {  
            synchronized (mSelfObserverLock) {  
                mContentObservable.dispatchChange(selfChange);  
                if (mNotifyUri != null && selfChange) {  
                    mContentResolver.notifyChange(mNotifyUri, mSelfObserver);  
                }  
            }  
    }  

    我们可以看到 它会触发mContentObservable这个目标对象去调用dispatchChange()方法

    public void dispatchChange(boolean selfChange) {  
            synchronized(mObservers) {  
                for (ContentObserver observer : mObservers) {  
                    if (!selfChange || observer.deliverSelfNotifications()) {  
                        observer.dispatchChange(selfChange);  
                    }  
                }  
     }  

    到这里,它接着就通知其注册的各个Observer去执行dispatchChange()方法,前面我们已经知道了mContentObservable了被注册了ChangeObserver 的实例 mChangeObserver,这里呢首先会执行ChangeObserver的父类ContentObserver的dispatchChange(false)方法:

    public final void dispatchChange(boolean selfChange) {  
            if (mHandler == null) {  
                onChange(selfChange);  
            } else {  
                mHandler.post(new NotificationRunnable(selfChange));  
            }  
    }  

    接着就来到其子类实例mChangeObserver的dispatchChange()方法:

    private class ChangeObserver extends ContentObserver {  
            public ChangeObserver() {  
                super(new Handler());  
            }  
      
            @Override  
            public boolean deliverSelfNotifications() {  
                return true;  
            }  
      
            @Override  
            public void onChange(boolean selfChange) {  
                onContentChanged();  
            }  
    }  

    在其Onchange()方法中调用了onContentChanged()方法:

    protected void onContentChanged() {  
            if (mAutoRequery && mCursor != null && !mCursor.isClosed()) {  
                mDataValid = mCursor.requery();  
            }  
    }  

    到这里 我们是不是恍然大悟了,mCursor.requery()则就会重新刷新并填充mCursor对象。然后还没有结束:我们的cursor重新填充了,但是不会告诉Adapter执行notifyDataSetChanged()方法,因为只有执行了这个方法,我们的界面才会刷新。

    所以我们接着看下mCursor.requery()的内部做了些什么:

    public boolean requery() {  
            if (mSelfObserver != null && mSelfObserverRegistered == false) {  
                mContentResolver.registerContentObserver(mNotifyUri, true, mSelfObserver);  
                mSelfObserverRegistered = true;  
            }  
            mDataSetObservable.notifyChanged();  
            return true;  
    }  

    我们可以看到,mDataSetObservable.notifyChanged();这个就会 会触发mDataSetObservable去通知其内部注册的observer,前面我们也讲了mDataSetObservable被注册了 CursorAdapter中的 MyDataSetObserver的实例 mDataSetObserver,所以我们接着看下mDataSetObserver的onchange()方法的实现:

    private class MyDataSetObserver extends DataSetObserver {  
            @Override  
            public void onChanged() {  
                mDataValid = true;  
                notifyDataSetChanged();  
            }  
      
            @Override  
            public void onInvalidated() {  
                mDataValid = false;  
                notifyDataSetInvalidated();  
            }  
    }  

    在该方法中调用了 notifyDataSetChanged();  这个方法干嘛了呢,我们不仅要问,是不是它就是用来刷新界面呢?这个方法用的是子父类Baseadapter的,

    BaseAdapetr:

    public void notifyDataSetChanged() {
            mDataSetObservable.notifyChanged();
        }

    我们可以看到,在其源码中,它会调用其父类BaseAdapetr中mDataSetObservable去通知其中被注册的Observer,那这个observer到底在哪里被注册的呢,这里呢 也就不饶弯子了一步到位,回到我们使用CursorAdapter的最初,但我们初始化完成它的时候,我们是不是接着会调用setAdapter()方法,将该Adapter设置到目标列表中,那么这里又做了什么呢?

     public void setAdapter(ListAdapter adapter) {
    
           ...省略
    
            if (mAdapter != null) {
               
           ...省略
    
                mDataSetObserver = new AdapterDataSetObserver();
                mAdapter.registerDataSetObserver(mDataSetObserver);
    
                 ...省略
    
    
            requestLayout();
        }

    在这里我们找到了我们的答案,原来这个被注册的observer就是AdapterDataSetObserver,那这下就好啦,我们转到其内部的onchange()去一探究竟:

     public void onChanged() {
                mDataChanged = true;
                mOldItemCount = mItemCount;
                mItemCount = getAdapter().getCount();
    
                // Detect the case where a cursor that was previously invalidated has
                // been repopulated with new data.
                if (AdapterView.this.getAdapter().hasStableIds() && mInstanceState != null
                        && mOldItemCount == 0 && mItemCount > 0) {
                    AdapterView.this.onRestoreInstanceState(mInstanceState);
                    mInstanceState = null;
                } else {
                    rememberSyncState();
                }
                checkFocus();
                requestLayout();
            }

    果不其然,原来它通过 requestLayout();来完成接下来的操作了去刷新界面,其内部就是Android中View的绘制机制了,感兴趣的话可以去了解哦!

     到这里,本章内容就全部讲完啦!嘎嘎~  Ps: 有不对的还请及时指出哦!

     
  • 相关阅读:
    聊聊自动化的打开方式
    浅谈如何提高自动化测试的稳定性和可维护性 (pytest&allure)
    Jmeter做压力测试的心得
    为什么测试人员必须掌握Linux?
    数据结构与算法系列 目录
    高可用高性能分布式文件系统FastDFS进阶keepalived+nginx对多tracker进行高可用热备
    Fastdfs文件系统扩容
    Linux下FastDFS分布式存储-总结及部署记录
    How to setup a Alpine Linux mirror
    修改内核参数开启转发
  • 原文地址:https://www.cnblogs.com/kevinOne/p/4306154.html
Copyright © 2020-2023  润新知