嵌套两层滑动view下,IllegalArgumentException: pointerIndex out of range的解决方法


----------------------发现问题期间的一些记录,日期是后面补充的,不一定准确,不想看可以直接翻到下面。---------------------------

2014年10月17日23:48:11

10-17 17:51:26.370: W/System.err(2789): java.lang.IllegalArgumentException: pointerIndex out of range

10-17 17:51:26.370: W/System.err(2789): at android.view.MotionEvent.nativeGetAxisValue(Native Method)

10-17 17:51:26.375: W/System.err(2789): at android.view.MotionEvent.getX(MotionEvent.java:2148)

(debug,看看getX(传入了什么参数,返回了什么参数

10-17 18:02:55.385: W/System.err(5522):  at android.widget.HorizontalScrollView.onTouchEvent(HorizontalScrollView.java:807)
(debug,看看传入了什么参数,返回了什么参数




- -- -------------------------------------------------------- -以上可以忽略 ---------------------------------------------


2014年10月19日15:48:46

HorizontalScrollView 里嵌套了一个类似viewpager的view。
重写了onInterceptTouch Event  和 onTouchEvent 之后,
滑动内层,报下列错误。google 百度 stackoverfloew 有相关的问题,但无法解决。

网络上try catch  IllegalArgumentException,或者return false什么的,不能解决。

java.lang.IllegalArgumentException: pointerIndex out of range
at android.view.MotionEvent.nativeGetAxisValue(Native Method)
at android.view.MotionEvent.getX(MotionEvent.java:2148)


2014年10月19日17:25:14

重写了,Menu的onInterceptTouchEvent 之后, return 的值被我人为的限定成(true  false),并没有调用super.onInterceptTouchEvent。

这时,如果条件满足拦截下了Touch事件,就会进入Menu的onTouchEvent。

在该方法最后的返回值为:super.onTouchEvent(ev);  

意味着,返回值是通过父类HorizontalScrollView 的 onTouchEvent 计算得出的。

在父类的onTouchEvent  里面

 
    
case MotionEvent.ACTION_MOVE:
/*这里必定会取出-1.原因是因为在down事件的时候,onInterceptTouchEvent没有对activePointerIndex 进行合理赋值。*/
final int activePointerIndex = ev.findPointerIndex(mActivePointerId);
if (activePointerIndex == -1) {
Log.e(TAG, "Invalid pointerId=" + mActivePointerId + " in onTouchEvent");
break;
}

Log.e(TAG,"Invalid pointerId="+ mActivePointerId +" in onTouchEvent");

所以Android 4.4 就会输出这一句。

Invalid pointerId=-1 in onTouchEvent

Android  4.4以下,很可能会输出:

 
    
java.lang.IllegalArgumentException: pointerIndex out of range
at android.view.MotionEvent.nativeGetAxisValue(Native Method)
at android.view.MotionEvent.getX(MotionEvent.java:2148)
pointerIndex out of range

pointerIndex 不在合理范围之内,是因为其值为-1。

 

结论:

由于没有调用 super.onInterceptTouchEvent(); 造成 mActivePointerIdactivePointerIndex的值不能正确获取

导致父类 onTouchEvent取值错误,最终 onTouchEvent不能正确执行。



解决方法:

解决方法很简单,只要在重写过的 onInterceptTouchEvent里面 添加 super.onInterceptTouchEvent();既可。

注意,根据你的需求来return 相应的值,不一定要return 它,只需要调用。

目的是为了让父类的onInterceptTouchEvent 获得正确的参数。

例如mActivePointerIdactivePointerIndex 等。



思考:

为什么会出以上的问题?

首先,检讨自己对android系统的执行流程、原理不熟悉,就随意重写系统方法。


但是在出错之后,我是如何发现解决方法的呢?

走过许多弯路。百度 google stackflowover github 同有人有相同的问题,但不能完美解决。

最早,重写了onInterceptTouchEvent,并且,根据项目需求,写出拦截逻辑之后。

就出现了刚刚提到的报错提示。

1 由于报错来自系统,就忽略。一直以来都容易忽略系统级别的错误提示 ,需要反思。

2 改写逻辑,发现还是同样提示(反复调试修改、看一切关于Touch事件的文章,费时2天左右,无实际进展,但是默默积累了Touch事件的知识)。

3 通过搜索,发现只要是如此嵌套和重写onInterceptTouchEvent 就会出现该问题。

4 重新审视报错提示。

5 反复进入系统源码跟踪调错调错调错调错,最终发现问题

    在这个过程中,得到经验教训:

如果要调试系统源码,必须要用官方的虚拟机,相应版本的sdk,以及相应版本的编译target。只有这样才能正确debug系统源码。不然你会发现,debug 的时候没有章节、不合理的跳来跳去。

   真机和genymotion的系统能否完全对应sdk的源码?无法确定, 因此,不要以为有了 真机 或 genymotion就无敌了。

X86的ABI虽然流畅,但是会有莫名其妙的问题,建议还是用ARM。



2014年10月19日15:48:46

    

这样子,内外层都能滑动,而且不冲突了。



结论:

由于没有调用 super.onInterceptTouchEvent(); 造成 mActivePointerIdactivePointerIndex的值不能正确获取

导致父类 onTouchEvent取值错误,最终 onTouchEvent不能正确执行。

你可能感兴趣的:(Android)