今天遇到以下异常:

java.lang.IllegalStateException: The application's PagerAdapter changed the adapter's
contents without calling PagerAdapter#notifyDataSetChanged!

在描述问题解决之前,先说下项目列表显示的机制吧
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()方法就解决问题了!

记录下来,加深印象!

转载于:https://www.cnblogs.com/dzboy/p/3629049.html

ViewPager异常,对ViewPager源码分析相关推荐

  1. android view 源码分析,Android ViewPager源码详细分析

    1.问题 由于Android Framework源码很庞大,所以读源码必须带着问题来读!没有问题,创造问题再来读!否则很容易迷失在无数的方法与属性之中,最后无功而返. 那么,关于ViewPager有什 ...

  2. illegalstateexception是什么异常_异常源码分析—告诉你学习“源码”究竟有什么用!...

    点击上方"服务端思维",选择"设为星标" 回复"669"获取独家整理的精选资料集 回复"加群"加入全国服务端高端社群「后 ...

  3. 鸿蒙轻内核源码分析:异常钩子模块系统中断异常,如何转储异常信息

    摘要:本篇介绍下鸿蒙轻内核中异常钩子模块发生系统中断异常时如何转储异常信息. 本文分享自华为云社区<鸿蒙轻内核M核源码分析系列十七(3) 异常信息ExcInfo>,作者: zhushy. ...

  4. dubbo注册服务IP解析异常及IP解析源码分析

    https://www.cnblogs.com/leo-li-3046/p/5702479.html 在使用dubbo注册服务时会遇到IP解析错误导致无法正常访问. 比如: 本机设置的IP为172.1 ...

  5. v39.06 鸿蒙内核源码分析(异常接管) | 社会很单纯 复杂的是人 | 百篇博客分析HarmonyOS源码

    子曰:"主忠信,毋友不如己者,过则勿惮改." <论语>:子罕篇 百篇博客系列篇.本篇为: v39.xx 鸿蒙内核源码分析(异常接管篇) | 社会很单纯 复杂的是人 硬件 ...

  6. scroller类的用法完全解析以及带源码分析

    上一篇:scrollTo与scrollBy用法以及TouchSlop与VelocityTracker解析 通过上一篇内容对scrollTo与scrollBy用法以及TouchSlop与Velocity ...

  7. PackageInstaller源码分析(一)

      本篇博客分析PackageInstaller源码目的是分析Android权限机制,Android App的权限在应用被安装时,用户选择授予或者拒绝.所以,分析Android权限机制源码的第一步分析 ...

  8. 仿爱奇艺视频,腾讯视频,搜狐视频首页推荐位轮播图(二)之SuperIndicator源码分析

    转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼:http://blog.csdn.net/hejjunlin/article/details/52510431 背景:仿爱奇艺视频,腾讯视频 ...

  9. TouchImageView源码分析

    TouchImageView源码分析--请叫我代码侦探 github上有个不错得项目,https://github.com/Dreddik/AndroidTouchGallery 主要还是TouchI ...

  10. 字节跳动Android三面视频解析:framework+MVP架构+HashMap原理+性能优化+Flutter+源码分析等

    前言 对于字节跳动的二面三面而言,Framework+MVP架构+HashMap原理+性能优化+Flutter+源码分析等问题都成高频问点!然而很多的朋友在面试时却答不上或者答不全!今天在这分享下这些 ...

最新文章

  1. 走过求职的季节(2)-十月 龙卷风
  2. 2021牛客多校10 - Browser Games(哈希)
  3. 联想云计算机终端,联想云桌面
  4. 便签如何把短音频文件mp3的转换成文字
  5. 路由守卫 Maximum call stack size exceeded
  6. 3D动画建模软件市场现状研究分析
  7. 基于STM32超声波测距
  8. 餐巾计划问题【网络流24题】
  9. voyage java_Voyage:Java 实现的基于 Netty 的轻量、高性能分布式 RPC 服务框架
  10. 图像处理之细化算法(Thinning Algorithm)C++实现
  11. 搭建一个vue小页面(入门vue)
  12. 联想小新Air13高定黑使用初体验
  13. 国防科技大学计算机系邹革新,国防科技大学机电工程与自动化学院――邹逢兴教授...
  14. Capto2022中文版一款适用Mac屏幕录制编辑软件
  15. java 多重继承的困境
  16. 计算机操作处于挂起状态,计算机重新启动操作可能处于挂起状态怎么办?
  17. Vue路由守卫(拦截)
  18. buc算法java实现,数据挖掘概念与技术(hanjiawei)阅读笔记--第五章(数据立方体技术)...
  19. BZOJ 3165 Heoi2013 Segment 线段树
  20. 病毒式营销活动策划书

热门文章

  1. python中的turtle如何运行_python中turtle库的简单使用教程
  2. linux百分比查看文件,Linux 如何查看内存使用率百分比?
  3. Android NDK开发之 Android系统开发中LOG的使用
  4. eclipse断点不能下一步_大盘下一步这样走,不能错过
  5. 分布式数据库的最新发展情况
  6. 再论DataSet与DataFrame的区别
  7. kafka offset入门理解
  8. C++Lambda表达式作为参数
  9. QT_在循环中刷新界面
  10. 微信小程序自定义弹窗组件