0

这段代码

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(请参阅文档)。

我知道做的唯一奇怪的事情是我GLSurfaceView.queueEvent用来传递MotionEvent到 GL 表面的渲染线程进行处理:

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

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

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

问题:这里真正出了什么问题?

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

4

2 回答 2

0

根据您提到的文档,您需要在 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));
    }
}
于 2013-04-10T16:56:47.103 回答
0

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

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

于 2013-05-07T18:41:49.693 回答