Reputation: 1671
I'm using a SurfaceView
to draw touches as an overlay over my app. I would like my other View
s to be able to respond to touch events while at the same time as the SurfaceView
so in the ViewGroup
that contains them both I added
MyViewGroup:
@Override
public boolean onInterceptTouchEvent(MotionEvent motionEvent){
mSurfaceView.onTouchEvent(motionEvent);
return false;
}
Since the SurfaceView
sits behind the other views, this works great. Both the SurfaceView
and the View
on top of it receive the MotionEvent
.
The SurfaceView
then further forwards the event to the thread rendering into it.
MySurfaceView:
@Override
public boolean onTouchEvent(MotionEvent motionEvent) {
if (mThreadHandler != null){
mThreadHandler.sendMotionEvent(motionEvent);
}
return true;
}
Then when my rendering thread receives the message it runs:
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;
}
}
When I run this code in debug mode and swipe my finger across the ViewGroup
the values for x
, x2
, and x3
all differ. I suspect this is because the UI thread is re-using the MotionEvent before it has been consumed by MyRenderThread
. How can I fix this?
The bad solution would be to copy each MotionEvent
as a new object and pass that to MyRenderThread
, but this requires a lot of object creation/destruction.
Upvotes: 3
Views: 2270
Reputation: 1671
MotionEvent.obtain(MotionEvent ev)
will return a MotionEvent
from the pool that is a copy of the input event.
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.
}
This way each event is still copied (not sure what to do about that) but at least the objects are reused.
Upvotes: 2