つまり、簡単に言うと、マルチタッチに使用していたハンドラーがクラッシュし、「IllegalArgumentException: pointerIndex out of range」がスローされました。
エラーをキャッチしようとしましたが、(x, y) がデフォルトで (min.x, max.y) になり、私の場合は (0.0, 480.0) になることに気付きました。
かなりいじり回した後、エラーはタッチをスパムしているときにのみ発生することがわかりましたが、2つの異なる場所を交互に十分にすばやくタップするだけで、具体的かつ非常に定期的に再現できました(ただし、通常のマルチタッチゲーム中に発生するほど遅い). .
onTouch メソッドは次のとおりです。
public boolean onTouch(View v, MotionEvent event) {
synchronized (this) {
int pointerIndex = (event.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
int pointerId = event.getPointerId(pointerIndex);
TouchEvent touchEvent;
// pointerId fix
if (pointerId >= event.getPointerCount() && pointerId > 0)
pointerId--;
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN:
touchEvent = touchEventPool.newObject();
touchEvent.type = TouchEvent.TOUCH_DOWN;
touchEvent.pointer = pointerId;
try {
touchEvent.x = touchX[pointerId] = (int) (event
.getX(pointerId) * scaleX);
touchEvent.y = touchY[pointerId] = (int) (event
.getY(pointerId) * scaleY);
} catch (IllegalArgumentException e) {
Log.d("multiTouchHandler", e.toString() + ":: PID = "
+ pointerId);
}
isTouched[pointerId] = true;
touchEventsBuffer.add(touchEvent);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
touchEvent = touchEventPool.newObject();
touchEvent.type = TouchEvent.TOUCH_UP;
touchEvent.pointer = pointerId;
try {
touchEvent.x = touchX[pointerId] = (int) (event
.getX(pointerIndex) * scaleX);
touchEvent.y = touchY[pointerId] = (int) (event
.getY(pointerIndex) * scaleY);
} catch (IllegalArgumentException e) {
Log.d("multiTouchHandler", e.toString() + ":: PID = "
+ pointerId);
}
isTouched[pointerId] = false;
touchEventsBuffer.add(touchEvent);
return false;
case MotionEvent.ACTION_MOVE:
int pointerCount = event.getPointerCount();
for (int i = 0; i < pointerCount; i++) {
touchEvent = touchEventPool.newObject();
touchEvent.type = TouchEvent.TOUCH_DRAGGED;
touchEvent.pointer = pointerId;
try {
touchEvent.x = touchX[pointerId] = (int) (event
.getX(pointerIndex) * scaleX);
touchEvent.y = touchY[pointerId] = (int) (event
.getY(pointerIndex) * scaleY);
} catch (IllegalArgumentException e) {
Log.d("multiTouchHandler", e.toString() + ":: PID = "
+ pointerId);
}
isTouched[pointerId] = false;
touchEventsBuffer.add(touchEvent);
}
break;
case MotionEvent.ACTION_CANCEL:
}
return true;
}
}
Log.d 出力から発生しているように見えたのは、pointerId が次に使用可能なポインター (例 1) に割り当てられることがあるが、実際のポインター データは以前のポインターの場所 (0) に格納されることでした。
pointerId が現在の pointerCount の範囲外であるかどうかを確認し、そうである場合は 1 つ前に戻ることで、少なくとも 2 行のコードで 2 本の指の問題を修正することができました。
// pointerId fix
if (pointerId >= event.getPointerCount() && pointerId > 0)
pointerId--;
これで本当に問題が解決するかどうかはわかりませんが、タッチ スクリーンの fps ゲームで使用されるような 2 本指のマルチタッチ コントロールではうまく機能するようです。私自身のテストでは、例外なく両方のポイントからのタッチを正確に判断し、正しい (x, y) 値を保存できることが示されました。
より良い解決策はありますか、それともポインター ID のマルチタッチ API の使用は本当に悪いのでしょうか? 知りたい人がいれば、これは 4.0.3 デバイス上にありました。