即使索引在范围内,getPointerId也会抛出异常

时间:2012-09-03 19:09:17

标签: android multi-touch

此代码

android.view.MotionEvent event = ...;

for(int i = 0, n = event.getPointerCount(); i < n; i++)
{
    handleTouch(event.getPointerId(i), event.getX(i), event.getY(i));
}

零星地抛出IllegalArgumentException

09-03 19:43:21.996 E/AndroidRuntime( 9484): FATAL EXCEPTION: GLThread 732
09-03 19:43:21.996 E/AndroidRuntime( 9484): java.lang.IllegalArgumentException: pointerIndex out of range
09-03 19:43:21.996 E/AndroidRuntime( 9484):     at android.view.MotionEvent.nativeGetPointerId(Native Method)
09-03 19:43:21.996 E/AndroidRuntime( 9484):     at android.view.MotionEvent.getPointerId(MotionEvent.java:1927)

这似乎是不可能的,因为getPointerId被记录为从0 getPointerCount()-1获取指数(见the documentation)。

我所知道的唯一奇怪的事情是我使用GLSurfaceView.queueEventMotionEvent传递给GL表面的渲染线程进行处理:

public boolean onTouchEvent(final MotionEvent event)
{
    queueEvent(new Runnable() {
        public void run() {
            worker.handleTouchEvent(event);
        }
    });
    return true;
}

我正在获取一个我认为应该是不可变的对象的引用,我想我正安全地将它传递给另一个线程进行处理,我只进行只读访问。

因此我将访问实际MotionEvent对象的代码移动到UI线程,但由于问题很少发生,我不知道在应用程序发布之前我是否真正解决了问题。

问题:这里到底出了什么问题?

后续问题:假设这与我使用多线程有关,如何我如何安全地将MotionEvent发送到另一个线程?

2 个答案:

答案 0 :(得分:0)

根据您提到的the documentation,您需要在getX(),getY()的调用中使用从findPointerIndex()获得的索引:

for (int i = 0, n = event.getPointerCount(); i < n; i++)
{
    int pid = event.getPointerId(i);
    int index = event.findPointerIndex(pid);
    if (index != -1)
    {
        handleTouch(pid, event.getX(index), event.getY(index));
    }
}

答案 1 :(得分:0)

经过进一步测试,我现在确信Android框架确实在onTouchEvent返回后重新使用了MotionEvent对象。

因此,不能将事件对象视为不可变对象;特别是,它不应该保持在事件处理函数的末尾之外,或者传递给另一个线程。