MotionEvent在仍在使用时被回收

时间:2014-09-19 21:31:04

标签: android multithreading surfaceview ontouchevent motionevent

我使用SurfaceView绘制触摸作为我的应用的叠加层。我希望我的其他View能够在SurfaceView的同时响应触摸事件,因此在包含它们的ViewGroup中我添加了

MyViewGroup:

@Override
public boolean onInterceptTouchEvent(MotionEvent motionEvent){
    mSurfaceView.onTouchEvent(motionEvent);
    return false;
}

由于SurfaceView位于其他视图后面,因此效果很好。其顶部的SurfaceViewView都会收到MotionEvent

SurfaceView然后进一步将事件转发给呈现它的线程。

MySurfaceView:

@Override
public boolean onTouchEvent(MotionEvent motionEvent) {
    if (mThreadHandler != null){
        mThreadHandler.sendMotionEvent(motionEvent);
    }
    return true;
}

然后当我的渲染线程收到它运行的消息时:

MyRenderThread:

private void handleMotionEvent(MotionEvent motionEvent){
    switch (motionEvent.getAction()){
        case MotionEvent.ACTION_DOWN:
            float x = motionEvent.getX();                          // Breakpoint 1
            float x2 = motionEvent.getX();                         // Breakpoint 2
            float x3 = motionEvent.getX();                         // Breakpoint 3
            path.moveTo(motionEvent.getX(), motionEvent.getY());
            break;
        case MotionEvent.ACTION_MOVE:
            path.lineTo(motionEvent.getX(),motionEvent.getY());
            break;
        case MotionEvent.ACTION_UP:
        case MotionEvent.ACTION_CANCEL:
                // do nothing
            break;
        default:
            break;
   }
}

当我在调试模式下运行此代码并在ViewGroup上扫描x时,x2x3的值都不同。我怀疑这是因为UI线程在被MyRenderThread使用之前重新使用了MotionEvent。我该如何解决这个问题?

糟糕的解决方案是将每个MotionEvent复制为新对象并将其传递给MyRenderThread,但这需要很多对象创建/销毁。

1 个答案:

答案 0 :(得分:1)

MotionEvent.obtain(MotionEvent ev)将从池中返回MotionEvent,它是输入事件的副本。

MyViewGroup:

@Override
public boolean onInterceptTouchEvent(MotionEvent motionEvent){
    mSurfaceView.fowardTouchEvent(MotionEvent.obtain(motionEvent); 
    return false;
}

MySurfaceView:

public void forwardTouchEvent(MotionEvent motionEvent){
    if (scratchpadThreadHandler != null){
        scratchpadThreadHandler.sendMotionEvent(motionEvent);
    }
}

MyRenderThread:

private void handleMotionEvent(MotionEvent motionEvent){
    switch (motionEvent.getAction()){
        case MotionEvent.ACTION_DOWN:
            float x = motionEvent.getX();                          // Breakpoint 1
            float x2 = motionEvent.getX();                         // Breakpoint 2
            float x3 = motionEvent.getX();                         // Breakpoint 3
            path.moveTo(motionEvent.getX(), motionEvent.getY());
            break;
        case MotionEvent.ACTION_MOVE:
            path.lineTo(motionEvent.getX(),motionEvent.getY());
            break;
        case MotionEvent.ACTION_UP:
        case MotionEvent.ACTION_CANCEL:
                // do nothing
            break;
        default:
            break;
   }
    motionEvent.recycle();  // Mark this MotionEvent as available for recycling.
}

这样每个事件仍然被复制(不知道该怎么办),但至少会重用这些对象。