Play控制台每日重复出现ViewPager相关IllegalArgumentException崩溃求助
解决ViewPager引发的MotionEvent.getX() IllegalArgumentException崩溃
首先咱们拆解下这个崩溃的核心原因:从堆栈信息能看到,崩溃触发在ViewPager.onInterceptTouchEvent调用MotionEvent.getX()时抛出IllegalArgumentException,这基本都是因为传入的触摸点索引(pointerIndex)无效——比如某个触摸点已经抬起,但代码还在尝试用旧索引获取坐标,就会触发这个问题。结合你的图片类应用场景(ViewPager轮播+ListView),大概率是旧版support库的ViewPager存在触摸事件处理bug,或是ViewPager与ListView之间的触摸事件传递冲突导致的。
下面是几个针对性的解决方案,按优先级排序:
1. 升级依赖库(最推荐)
你当前用的是android.support.v4.view.ViewPager,这个旧support库早已停止维护,其中确实存在触摸事件处理的已知bug。建议直接迁移到AndroidX的ViewPager,或者至少把support库升级到它的最终稳定版本:
- 若还在使用support库,确保
com.android.support:support-v4版本升级到28.0.0(support库最后一个稳定版) - 更推荐迁移到AndroidX,替换为
androidx.viewpager:viewpager:1.0.0及以上版本,AndroidX修复了大量旧support库的遗留bug
2. 自定义ViewPager,添加触摸点索引有效性检查
如果暂时无法升级依赖库,可以自定义一个ViewPager,重写触摸事件相关方法,提前检查索引合法性,避免崩溃:
public class SafeViewPager extends ViewPager { public SafeViewPager(Context context) { super(context); } public SafeViewPager(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { try { // 非按下事件时,先检查触摸点索引是否合法 if (ev.getActionMasked() != MotionEvent.ACTION_DOWN) { int pointerIndex = ev.getActionIndex(); if (pointerIndex < 0 || pointerIndex >= ev.getPointerCount()) { return false; } } return super.onInterceptTouchEvent(ev); } catch (IllegalArgumentException e) { // 兜底捕获异常,防止崩溃扩散 e.printStackTrace(); return false; } } @Override public boolean onTouchEvent(MotionEvent ev) { try { // 同样在触摸事件处理里做防护 if (ev.getActionMasked() != MotionEvent.ACTION_DOWN) { int pointerIndex = ev.getActionIndex(); if (pointerIndex < 0 || pointerIndex >= ev.getPointerCount()) { return false; } } return super.onTouchEvent(ev); } catch (IllegalArgumentException e) { e.printStackTrace(); return false; } } }
之后把布局文件里的android.support.v4.view.ViewPager替换成你自定义的SafeViewPager即可。
3. 排查ViewPager与ListView的触摸事件冲突
如果你的ListView是嵌套在ViewPager内部的,可能会出现触摸事件传递混乱的情况,进一步触发这个bug。可以尝试:
- 给ListView设置
setOnTouchListener,在触摸时判断滑动方向:当用户横向滑动且ListView处于顶部/底部时,让ViewPager拦截事件 - 把ListView的
overScrollMode设置为never,避免过度滚动时干扰触摸事件的正常传递
内容的提问来源于stack exchange,提问作者Deb Prakash Chatterjee
相关产品推荐
相关产品推荐

