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

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

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

 

                ContentProvider和Cursor以及CursorAdapter三者之间内部链接实现原理 解析_第1张图片

   上面说到观察者模式的运用 第一处在于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: 有不对的还请及时指出哦!

 

 

 

你可能感兴趣的:(ContentProvider)