----------------------发现问题期间的一些记录,日期是后面补充的,不一定准确,不想看可以直接翻到下面。---------------------------
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(传入了什么参数,返回了什么参数
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 不在合理范围之内,是因为其值为-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。
结论:
由于没有调用 super.onInterceptTouchEvent(); 造成 mActivePointerIdactivePointerIndex的值不能正确获取。
导致父类 onTouchEvent取值错误,最终 onTouchEvent不能正确执行。