forget to call notifyDatasetChanged 错误
这几天一直在完善之前自己的写的Android应用。想用ViewPager让之前界面能够滑动阅读。但是滑动过程中,经常会莫名其妙地遇到一个问题。莫名其妙地提示ViewPager expected 10 counts,but found 20. forget to call notifyDatasetChanged. 意思很明显,就是ViewPager的数据集改变了,但是我却忘了去通过notifyDatasetChanged去通知PagerAdapter数据已经更新了。但是我其实在那个页面压根没有去更新数据。不过根据提示显然是因为哪个地方改变了数据的数量。还好我动态更新数据的地方不多。检查一下代码,根据自己的思路,立刻发现了问题。我会在已经载入当前列表的时候,去服务器取下一个列表。这样在我取完下一个列表的时候,数据就变了。然后就出现那个问题了。
虽然没怎么浪费时间就解决了问题,但是在面对多个线程数据共享的时候确实得增加一些额外的考虑。PagerAdapter的数据如果改变,是需要调用notifyDatasetChanged方法的。多线程的共享需要考虑同步的问题,这个同步不仅仅是一个synchronize就能够避免的,每个线程都需要去预防共享的数据被另外一个线程更改了。
ViewPager与Fragment
我在使用ViewPager的时候,使用了FragmentStatePagerAdapter作为它的Adapter,因为会有很多Fragment,如何从ViewPager控制它的Fragment就成了一个问题。
当然,直接保存ViewPager的所有Fragment似乎就能够控制了,但是这实在是不科学,保存起来太耗空间。而实际上ViewPager每次只有几个View保存着。当前显示的View以及前后几个View,在这之外的View都会被destory掉。这样能够很好地控制占用的内存。
但是幸运地是FragmentActivity的FragmentManager提供了一个getFragments的方法,该方法能够获取当前所有的Fragment。这样问题就解决了。获取Activity中所有的Fragment,然后判断是不是FragmentStatePagerAdapter的Fragment。这样ViewPager就能够直接控制它的Fragment Item了。
对于FragmentPagerAdapter与FragmentStatePagerAdapter的区别,FragmentPagerAdapter会对每一个Fragment进行缓存,而FragmentStatePagerAdapter不会。两个的使用方法是一样的。
notifyDatasetChanged做了什么工作?
每个Adapter都会有private DataSetObservable mObservable = new DataSetObservable();
一个DataSetObservable观察者。这个观察者可以注册registerDataSetObserver
。而notifyDatasetChanged函数做的就是通知注册这,我的数据已经改变了。
这样就给了ViewPager监听Adapter数据集变化的机会。在ViewPager的setAdapter中,有下面这段代码:
431 if (mAdapter != null) {
432 if (mObserver == null) {
433 mObserver = new PagerObserver();
434 }
435 mAdapter.registerDataSetObserver(mObserver);
436 mPopulatePending = false;
437 final boolean wasFirstLayout = mFirstLayout;
438 mFirstLayout = true;
439 mExpectedAdapterCount = mAdapter.getCount();
440 if (mRestoredCurItem >= 0) {
441 mAdapter.restoreState(mRestoredAdapterState, mRestoredClassLoader);
442 setCurrentItemInternal(mRestoredCurItem, false, true);
443 mRestoredCurItem = -1;
444 mRestoredAdapterState = null;
445 mRestoredClassLoader = null;
446 } else if (!wasFirstLayout) {
447 populate();
448 } else {
449 requestLayout();
450 }
451 }
在上面的代码中,注册了数据集变化的观察者。而notifyDatasetChanged就是通知观察者。
探究