まさかこんな実装をしているわけがない、と思います。僕くらいです。はい。おおonTouchメソッドよ死んでしまうとは情けない。
こうすると死ぬ
常識的に考えて以下のコードは気持ち悪いですよね。でもAndroid3.0未満、つまりGingerbread以前では問題なく動作します。しかしHoneycomb以降ではjava.lang.IllegalArgumentExceptionが発生してしまいます。エラーメッセージはpointerIndex out of rangeです。なんででしょうね?!
@Override
public boolean onTouchEvent(MotionEvent event) {
switch(event.getAction() & MotionEvent.ACTION_MASK){
case MotionEvent.ACTION_DOWN:
int x = event.getX(1);
break;
}
}
ソースを読む
MotionEventのソースを見ると・・・。げぇ全然違うぜぇえええ。
Android2.3.3_r1
public final float getX( int return mDataSamples[mLastDataSampleIndex + pointerIndex * NUM_SAMPLE_DATA + SAMPLE_X] + mXOffset; }
Android4.0.1
public final float getX(int pointerIndex) {
return nativeGetAxisValue(mNativePtr, AXIS_X, pointerIndex, HISTORY_CURRENT);
}
どう変わったか
上記の4.0.1のソースではもはやnativeメソッド。さすがに実装まで追うのはしんどいんで省略しますが、2.3.3_r1では配列アクセスをしている事がわかります。この配列はMotionEventのコンストラクタで初期化されます。配列サイズはコンストラクタに渡したpointerCount, sampleCountと定数NUM_SAMPLE_DATAを乗じた数となります。
private MotionEvent(int pointerCount, int sampleCount) {
mPointerIdentifiers = new int[pointerCount];
mDataSamples = new float[pointerCount * sampleCount * NUM_SAMPLE_DATA];
mEventTimeNanoSamples = new long[sampleCount];
}
現タッチ数は内部でmNumPointersで管理しています。2.3.3_r1のgetX(int)では利用していません。つまりgetX(int)でアクセスするインデックスに影響を与えません。MotionEventはイベントを受け取るViewで使い回しているので(一応MotionEventのhasCode()で確認した)、コンストラクタで確保された配列をオーバーしない限りは死なない事になります。
| 操作 | 実タッチ数 | Gingerbread以前 | Honeycomb以降 |
|---|---|---|---|
| event.getX(0) | 2 | ○ | ○ |
| event.getX(2) | 2 | ○ | × |
| event.getX(100000) | 2 | × | × |
結論
今までギリギリ動いていたけどHoneycomb、ICSで爆死、そんな事があるかもしれませんね。怖いわー。
0 コメント:
コメントを投稿