偶尔遇到页面ViewPager滑动时发生了如下错误:
java.lang.IllegalStateException: The application's PagerAdapter changed the adapter's contents without calling PagerAdapter#notifyDataSetChanged! Expected adapter item count: 11, found: 22
该错误的出处位于viewPager的populate方法:
final int pageLimit = mOffscreenPageLimit;
final int startPos = Math.max(0, mCurItem - pageLimit);
final int N = mAdapter.getCount();
final int endPos = Math.min(N-1, mCurItem + pageLimit);
if (N != mExpectedAdapterCount) {
String resName;
try {
resName = getResources().getResourceName(getId());
} catch (Resources.NotFoundException e) {
resName = Integer.toHexString(getId());
}
throw new IllegalStateException("The application's PagerAdapter changed the adapter's" +
" contents without calling PagerAdapter#notifyDataSetChanged!" +
" Expected adapter item count: " + mExpectedAdapterCount + ", found: " + N +
" Pager id: " + resName +
" Pager class: " + getClass() +
" Problematic adapter: " + mAdapter.getClass());
}
该方法会在很多地方被调用,比如ViewPager 每次翻页方法执行顺序:
dispatchKeyEvent->executeKeyEvent->arrowScroll->
pageLeft/pageRight->setCurrentItem->setCurrentItemInternal
在 setCurrentItemInternal 方法中,各种方法调用,会执行多次 populate() 方法,因此,会调用到多次 getCount()
来获取 N 的值
当 N != mExpectedAdapterCount 时便会发生如上错误,查阅源代码后发现 mExpectedAdapterCount 在dataSetChange方法出被赋值
void dataSetChanged() {
// This method only gets called if our observer is attached, so mAdapter is non-null.
final int adapterCount = mAdapter.getCount();
mExpectedAdapterCount = adapterCount;
// code here...
}
在 PagerAdapter 中调用 notifyDataSetChanged() 方法,数据更新的时候,mExpectedAdapterCount 会被重新赋值。
更新修改数据源一般是禁止在子线程中进行更新的。另外populate和notifyDataSetChanged两个方法都是在主线程中执行的,且有执行的先后顺序,所以如果发生了如上的错误,那么就需要查看数据修改和dataSetChange是否在主线程中连续的代码中执行,如果不是连续的主线程代码,那么在这两个动作间隔 viewPager的populdate 就有可能被调用,也就有可能发生上述错误。