我的ViewPager数据改变后,在切换界面刷新数据时:OnPageChangeListener中的数据IndexOutOfBoundsException,我们来看源码探一下究竟;

代码时这样写的:

vpLoveCar.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override
public void onPageSelected(int position) {
PreferenceUtil.set("OWNERCARVIN",carList.get(position).getVin_code());//记录当前索引,下拉刷新时更新该辆车;再次进入时显示该辆车;
} @Override
public void onPageScrollStateChanged(int state) { }
});

各种使用都没有问题,但是当carList的集合长度变化时(size变大后),我再去切换就会崩溃,这个问题足足影响了一个星期,我一直以为是数据操作的问题;直到今天我看了addOnPageChangeListener的源码。。。。。。

ViewPager的addOnPageChangeListener的源码:

private List<OnPageChangeListener> mOnPageChangeListeners;
private OnPageChangeListener mOnPageChangeListener;
/**
* Add a listener that will be invoked whenever the page changes or is incrementally
* scrolled. See {@link OnPageChangeListener}.
*
* <p>Components that add a listener should take care to remove it when finished.
* Other components that take ownership of a view may call {@link #clearOnPageChangeListeners()}
* to remove all attached listeners.</p>
*
* @param listener listener to add
*/
public void addOnPageChangeListener(@NonNull OnPageChangeListener listener) {
if (mOnPageChangeListeners == null) {
mOnPageChangeListeners = new ArrayList<>();
}
mOnPageChangeListeners.add(listener);
}

ViewPager的setOnPageChangeListener的源码:

/**
* Set a listener that will be invoked whenever the page changes or is incrementally
* scrolled. See {@link OnPageChangeListener}.
*
* @param listener Listener to set
*
* @deprecated Use {@link #addOnPageChangeListener(OnPageChangeListener)}
* and {@link #removeOnPageChangeListener(OnPageChangeListener)} instead.
*/
@Deprecated
public void setOnPageChangeListener(OnPageChangeListener listener) {
mOnPageChangeListener = listener;
}

由源码可知:addOnPageChangeListener这个方法,每调用一次都会添加一个OnPageChangeListener的监听,ViewPager会把这些监听存在一个List的集合中;所以我每次add一个监听,就会增加一个OnPageChangeListener,里面的数据也会有不同;会导致你有多个OnPageChangeListener,但是每个回调里面的position却是同样的,它去你集合长度小的那个里面OnPageChangeListener去获取数据,所以会下标越界异常;

源码提示让你在添加时去清空之前的OnPageChangeListener:

/**
* Remove all listeners that are notified of any changes in scroll state or position.
*/
public void clearOnPageChangeListeners() {
if (mOnPageChangeListeners != null) {
mOnPageChangeListeners.clear();
}
}

而setOnPageChangeListener这个方法,每调用一次都会新设置一个OnPageChangeListener的监听,ViewPager会替换你之前的监听; 用这个方法的话数据每次都是最新的,所以不会下表越界异常;

/**
* Remove a listener that was previously added via
* {@link #addOnPageChangeListener(OnPageChangeListener)}.
*
* @param listener listener to remove
*/
public void removeOnPageChangeListener(@NonNull OnPageChangeListener listener) {
if (mOnPageChangeListeners != null) {
mOnPageChangeListeners.remove(listener);
}
}

我最后的解决方式,有两种:

1、先清空在添加监听

vpLoveCar.clearOnPageChangeListeners();
vpLoveCar.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override
public void onPageSelected(int position) {
PreferenceUtil.set("OWNERCARVIN",carList.get(position).getVin_code());//记录当前索引,下拉刷新时更新该辆车;再次进入时显示该辆车;
} @Override
public void onPageScrollStateChanged(int state) { }
});

2、设置监听

vpLoveCar.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override
public void onPageSelected(int position) {
PreferenceUtil.set("OWNERCARVIN",carList.get(position).getVin_code());//记录当前索引,下拉刷新时更新该辆车;再次进入时显示该辆车;
} @Override
public void onPageScrollStateChanged(int state) { }
});

收获不小,我之前在使用这些方法没有出问题的时候,我一直认为addOnPageChangeListener和setOnPageChangeListener是一样的,知道今天改变数据后会下标越界异常;多去看一下源码还是有好处的;

ViewPager的addOnPageChangeListener和setOnPageChangeListener的区别,ViewPager改变数据后IndexOutOfBoundsException的更多相关文章

  1. [web] Get和Post区别,EncType提交数据的格式详解

    转载自:http://www.cnblogs.com/sunxucool/archive/2012/12/11/2813113.html 1. get是从服务器上获取数据,post是向服务器传送数据. ...

  2. Get和Post区别,EncType提交数据的格式详解——转自他人博客的

    1. get是从服务器上获取数据,post是向服务器传送数据. 2. get是把参数数据队列加到提交表单的ACTION属性所指的URL中,值和表单内各个字段一一对应,在URL中可以看到.post是通过 ...

  3. Kafka session.timeout.ms heartbeat.interval.ms参数的区别以及对数据存储的一些思考

    Kafka session.timeout.ms heartbeat.interval.ms参数的区别以及对数据存储的一些思考 在计算机世界中经常需要与数据打交道,这也是我们戏称CURD工程师的原因之 ...

  4. viewpager处理(三):让viewpager不预加载下一页

    有时候viewpager加载页面的时候,我们发现页面的数据量很大,预加载的话会消耗性能,为了节省用户流量和手机性能,所以我们想让viewpager不自动预加载下一页,怎么实现呢? viewpager预 ...

  5. 有关ViewPager的使用及解决Android下ViewPager和PagerAdapter中调用notifyDataSetChanged失效的问题

    ViewPager是android-support-v4.jar包中的一个系统控件,继承自ViewGroup,专门用以实现左右滑动切换View的效果,使用时需要首先在Project->prope ...

  6. ViewPager部分源码分析一:加载数据

    onMeasure()调用populate(),完成首次数据初始化. populate()维护ViewPager的page,包括mItems和mAdapter. populate(): if (cur ...

  7. viewpager处理(一):让viewpager不能滑动

    1.实现原理: 自定义viewpager,重写onTouchEvent方法,什么触摸事件都不响应即可让viewpager不能滑动. 2.代码如下 public class NoScrollViewPa ...

  8. python2与python3的区别 ,小数据池 bytes 类型

    一.python2和3的区别 在python3中 在python2中 print('ab')方式打印内容()括号是必须要有的.   print 'ab' 可以加可以不加. 只有range   有ran ...

  9. Linux与Windows的区别(后面了解后继续更新)

    1.转自知乎上的@Haoyuan Xing得答案: Linux是一个以开发者为中心的操作系统,Windows是以消费者为中心的操作系统.这是最根本的区别,也是Linux相对于Windows的优势/劣势 ...

随机推荐

  1. Java单播、广播、多播(组播)---转

    一.通信方式分类 在当前的网络通信中有三种通信模式:单播.广播和多播(组播),其中多播出现时间最晚,同时具备单播和广播的优点. 单播:单台主机与单台主机之间的通信 广播:当台主机与网络中的所有主机通信 ...

  2. javascript UI lib

    react 现在已经有JS,android,IOS版本的了 react作为View层的库,结合Flux react native Angular 是 MVVM, React 是 Flux(或者 MVC ...

  3. ElasticSearch:Lucene和ElasticSearch

    Lucene的概念: 关于索引 索引(index)和搜索(搜索),在lucene以及es里面索引是一个动作,即插入动作,包括创建索引以及为索引添加文档:所有则是针对索引(添加)的文档按照评分规则进行查 ...

  4. Ansible Ad-Hoc命令(三)

    一.Ad-Hoc 介绍 1.了解下什么是Ad-Hoc ? Ad-Hoc 其实就是基于Ansible 运行的命令集,有些类似终端中敲入的shell命令,Ansible提供了两种运行完成任务的方式,一种是 ...

  5. innobackupex

    time innobackupex --defaults-file=/data/mysql/3306/my.cnf --user=root --password=123456 \--rsync --p ...

  6. Mysql权限速查表以及权限详解

    一.前言 很多文章中会说,数据库的权限按最小权限为原则,这句话本身没有错,但是却是一句空话.因为最小权限,这个东西太抽象,很多时候你并弄不清楚具体他需要哪 些权限. 现在很多mysql用着root账户 ...

  7. 在windows server上配置java jdk后,可能要些时间生效。

    特别是程序调用java写的bat脚本时.

  8. 通过U盘启动vmware虚拟机

    不能通过虚拟机的USB功能,而是通过硬盘映射功能实现,操作方法如下图. 1.添加硬盘,注意接口类型与启动系统的支持(XPPE不支持scsi,但10pe支持) 2.硬盘类型 3.选择U盘映射 4.按F2 ...

  9. 【nosql】之ehcache.xml文件属性描述

    <ehcache updateCheck="false" name="shiroCache"> <defaultCache <!--最大 ...

  10. C++标准模板库(STL)介绍:set的基本用法

    1.元素的方向遍历 使用反向迭代器reverse_iterator可以反向遍历集合,输出集合元素的反向排序结果.它需要用到rbegin()和rend()两个方法,它们分别给出了反向遍历的开始位置和结束 ...