您的位置:首页 > 编程语言 > PHP开发

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

2015-02-28 20:07 459 查看
最近 在学习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: 有不对的还请及时指出哦!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐