今天遇到以下异常:

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. oracle dataguard详解,Oracle DataGuard数据备份方案详解
  2. linux php 升级5.3,Linux php5.2.10升级到PHP5.3.29
  3. webpack安装和配置
  4. python join函数用法-Python join()函数
  5. utf8 bom 去掉 java_utf-8-BOM删除bom
  6. Spring Cloud-honghu Cloud分布式微服务云系统
  7. Adreno GPU上的DirectX应用开发简介 (1)
  8. iconfont矢量图标库的引用方法
  9. 2021年3月CISSP考试顺利通过,超详细的经验介绍
  10. 有书共读:《穷查理宝典》
  11. 湖南科技大学c语言上机题库,2018年湖南科技大学计算机科学与工程院824C语言程序设计与数据结构综合之C程序设计考研核心题库...
  12. 前端高效开发必备的js库梳理,日常使用中会持续更新
  13. 计算机控制实验ppt模板,计算机控制技术实验课件.ppt
  14. 最新B站优秀C4D教程汇总(超干)
  15. windows连接蓝牙失败
  16. powershell导入脚本失败,禁止运行脚本,无法远程连接服务器
  17. EI会议-计算机领域
  18. C语言编程学习开发的俄罗斯方块小游戏
  19. 【Python】有红、黄、绿三种颜色的球,编程计算摸出球的各种颜色搭配
  20. 树莓派Bullseye系统安装QT

热门文章

  1. gstreamer插件开发_测评丨高性能多媒体处理器—飞凌OKMX8MM-C开发板
  2. python rest api client_Python py-jama-rest-client包_程序模块 - PyPI - Python中文网
  3. 安装 卸载 mysql linux,Linux 下MySQL 安装与卸载
  4. 三维计算机视觉(二)--点云滤波
  5. 图像分割(三)--Grab Cut
  6. 服务器的配置文档在哪里找,服务器端的数据库配置怎么找
  7. 分布式技术是大规模应用的最后一个考验
  8. Linux_开机自动挂载磁盘
  9. 详解多维数组与指针之间的关系
  10. 「美团 CodeM 复赛」城市网络