ViewPager异步添加数据异常 The application's PagerAdapter changed the adapter's contents without calling Pag

原创 2014年06月26日 14:55:24

项目中用到ViewPager左右滑动图片,图片从网上获取,异步添加到ViewPager的Adapter中。出现强关,log如下

06-25 15:01:44.396 E/AndroidRuntime(21181): java.lang.IllegalStateException: The application's PagerAdapter changed the adapter's contents without calling PagerAdapter#notifyDataSetChanged! Expected adapter item count: 6, found: 7 Pager id: com.fineos.music:id/focus_pager Pager class: class android.support.v4.view.ViewPager Problematic adapter: class com.fineos.music.HQadapter.OnlineFocusFragmentPagerAdapter
06-25 15:01:44.396 E/AndroidRuntime(21181): at android.support.v4.view.ViewPager.populate(ViewPager.java:962)
06-25 15:01:44.396 E/AndroidRuntime(21181): at android.support.v4.view.ViewPager.populate(ViewPager.java:914)
06-25 15:01:44.396 E/AndroidRuntime(21181): at android.support.v4.view.ViewPager.onMeasure(ViewPager.java:1436)
06-25 15:01:44.396 E/AndroidRuntime(21181): at android.view.View.measure(View.java:15623)

在描述问题解决之前,先说下项目列表显示的机制吧
1、数据:
  1)、Adapter接受到的是List,List容器中存放的是数据的实体类
  2)、所有View存放在Map中,getCount()方法返回的是Map的size
2、视图:
  1)、Adapter首先会根据List的大小和展现的View,预加载,这里是每次下载48条数据,每页12条,共4页
  2)、当ViewPager的滚动状态为IDLE的情况下,会以当前页为基准,向前创建一页View,向后创建两页View
  3)、所有View保存在Map中,当在调用instantiateItem方法的时候,直接从Map里边取
3、更新:
  1)、当数据下载完成,在主线程更改适配器中的List容器,并且调用notifyDataSetChanged();
  2)、onPageSelected触发会再次预加载的下一页数据,更新完毕还会执行上一步

好,进入正文
很多帖子提到ADT更新到22之后,检查更加严格,因此,每次数据更改都要调用notifyDataSetChanged方法,
我确实是这么做了,异步下载数据,下载完数据发送到主线程进行notifyDataSetChanged,结果,还是抛异常。
之前没看过ViewPager源码,这次就大概跟踪下方法吧!

通过搜索ViewPager类,找到异常抛出位置,在populate方法中

复制代码
 1 final int N = mAdapter.getCount();
 2 // code here ...
 3 if (N != mExpectedAdapterCount) {
 4   String resName;
 5   try {
 6     resName = getResources().getResourceName(getId());
 7   } catch (Resources.NotFoundException e) {
 8     resName = Integer.toHexString(getId());
 9   }
10   throw new IllegalStateException("The application's PagerAdapter changed the adapter's" +
11     " contents without calling PagerAdapter#notifyDataSetChanged!" +
12     " Expected adapter item count: " + mExpectedAdapterCount + ", found: " + N +
13     " Pager id: " + resName +
14     " Pager class: " + getClass() +
15     " Problematic adapter: " + mAdapter.getClass());
16 }
复制代码

关键就是mExpectedAdapterCount,那继续找mExpectedAdapterCount的声明和使用。
首先在setAdapter(PagerAdapter adapter)方法中找到赋值的地方,但是,不是设置适配器这个地方造成的异常,
所以,继续查找。
最后查找到的只有在dataSetChanged()中再次使用过,代码如下:

复制代码
1 void dataSetChanged() {
2     // This method only gets called if our observer is attached, so     mAdapter is non-null.
3 
4   final int adapterCount = mAdapter.getCount();
5   mExpectedAdapterCount = adapterCount;
6   // code here...
7 }
复制代码

在PagerAdapter中调用notifyDataSetChanged()方法,数据更新的时候,mExpectedAdapterCount会被重新赋值

mExpectedAdapterCount和N不同,那只能查下dataSetChanged()和populate()调用的先后顺序了
dataSetChanged()肯定是notifyDataSetChange()方法触发,那就查找populate()

不说分析的过程了,直接上结果!如下
ViewPager每次翻页方法执行顺序:
dispatchKeyEvent->executeKeyEvent->arrowScroll->
pageLeft/pageRight->setCurrentItem->setCurrentItemInternal

在setCurrentItemInternal方法中,各种方法调用,会执行多次populate()方法,因此,会调用到多次getCount()
来获取N的值,如下图

问题出来了,当翻页的时候,populate()方法会调用多次,直到状态为IDLE的时候,会创建预加载的一页视图,
此时,Adapter中存放View的Map会增加,getCount返回值变大。
这时候数据并未下载下来,那并不会notifyDataSetChanged()方法,mExpectedAdapterCount的值还是上次的值
因此,如下条件成立,进入代码,抛出异常

1 if (N != mExpectedAdapterCount) {
2 // code here...
3 }

如下图(最后一条Log为5,其实之后还会打印多次只是这时已经在populate()方法除抛异常,不会再继续执行):

==================================================================

仔细思考思考,其实是对notifyDataSetChanged()方法的调用时机有误解,并不是适配器数据更新的时候调用,
而是在getCount()发生改变的时候去调用,哪里影响了getCount(),就应该再哪里调用!
因此,在列表机制的第2-2步中去调用notifyDataSetChanged()方法。

也就是在ViewPager的滑动监听中的

            public void onPageScrollStateChanged(int i) {

方法中使用,判断state状态调用notify。

但是实际使用中,自动滑动没有问题,手动滑动依然会出现问题。

viewpager的adapter中的getcount方法如下

@Override
    public int getCount() {
        Log.d(TAG, "mOnlineFocusFragmentList mCount : " +
                (mOnlineFocusFragmentList == null ? 0 : mCount + 1) );
        return mOnlineFocusFragmentList == null ? 0 : mCount + 1;
    }

错误log依然同上。

从log往上看到,两个count的值一直都是相等的,当viewpager中的fragment的oncreateView 方法走到时,mCount的值发生变化,并且出现Exception。

所以在fragment的oncreateView和ondestroy方法加上 adapter的notify方法,问题解决!!


The application's PagerAdapter changed the adapter's contents without calling PagerAdapter

在我们的项目中,为了有好的

The application's PagerAdapter changed the adapter's contents without calling PagerAdapter#notifyDat

参考8、在初始化ViewPager时,应先给Adapter初始化内容后再将该adapter传给ViewPager,如果不这样处理,在更新adapter的内容后,应该调用一下adapter的notify...
  • cdnight
  • cdnight
  • 2015年08月28日 11:32
  • 2969

使用ViewPager时报出The application’s PagerAdapter changed the adapter’s contents without calling PagerAda

java.lang.IllegalStateException: The application's PagerAdapter changed the adapter's contents witho...

ViewPager报java.lang.IllegalStateException,without calling PagerAdapter#notifyDataSetChanged!

开发中第二次碰到这个问题: java.lang.IllegalStateException: The application's PagerAdapter changed the adapter's...

The application's PagerAdapter changed the adapter's contents without calling PagerAdapter#notifyDat

log信息如下:10-10 12:31:14.186: E/AndroidRuntime(22835): java.lang.IllegalStateException: The applicatio...
  • icewst
  • icewst
  • 2014年11月11日 11:43
  • 14012

关于viewpager的错误 java.lang.IllegalStateException: The application's PagerAdapter changed the adapter's

今天程序无意中出现了这样一个奇怪的错误,在网上查了一下说了很多解决方案,但是奇怪的是我使用了这么多次都没出现过这种问题,后来仔细查看自己的代码,发现数据来源用了一个全局List变量,在getCount...

The application's PagerAdapter changed the adapter's contents without calling PagerAdapter#notifyDat

在使用viewpager的过程中,有时候会动态的改变content,包括数量,有时候就会碰到这个问题: java.lang.IllegalStateException: The applicatio...

The application's PagerAdapter changed the adapter's contents without calling Pagapter

今天学习的时候爆出了这样一个关于ViewPager的错误: The application's PagerAdapter changed the adapter's contents without...

常见错误之java.lang.IllegalStateException: The application’s PagerAdapter changed the adapter’s cont。。。

如果在logcat日志中出现以下错误: java.lang.IllegalStateException: The application's PagerAdapter chang...

The application's PagerAdapter changed the adapter's contents without calling PagerAdapter#notifyDat

如果在logcat日志中出现以下错误:  01-22 09:24:42.271: E/AndroidRuntime(11279): java.lang.IllegalStateExcep...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:ViewPager异步添加数据异常 The application's PagerAdapter changed the adapter's contents without calling Pag
举报原因:
原因补充:

(最多只允许输入30个字)