onDoubleTapEventが連続して呼ばれる

GestureDetector.OnDoubleTapListenerを実装したクラスにて、ダブルタップでイベントを起こした場合、1度しかダブルタップしていないにもかかわらず何度かonDoubleTapEvent()が呼ばれるケースがあるということが判明した。

私は現在1つのアプリしか構築していないので、原因または、確実に現れるケースというものを把握出来ていないのだが、
こちら(http://bina1204.blog47.fc2.com/blog-entry-111.html)の方はMapViewで、私はSurfaceViewで発生している。
(MapViewではSurfaceViewが使われているのかな?)

とりあえず、連続で呼ばれてしまう場合に発生するイベントを追跡してみた結果
以下のように呼ばれている。

onDown → onShowPress → onSingleTapUp → onDoubleTap → onDoubleTapEvent
→ onDown(2回目) → onShowPress(2回目) → onDoubleTapEvent(2回目)

原因は分からないが、一部イベントが2度呼ばれている。
私のアプリはダブルタップしたあと、Messageを投げる仕組みになっているので、
そのへんが原因かもしれないと思ったが、やはり関係ないようで改善はされなかった。

とりえあず、原因がわかるまでは仕方ないので2度呼ばれないonDoubleTapにフラグを仕込むことで
2度目のonDoubleTapEventの際に処理が行われないようすることで対応した。

この手法は先に紹介したサイトの方のアイディアをいただきました。

androidは謎だ・・・

1.6 エミュレータの端末情報取得したメモ

コードはこちらを参考にしました。
http://kiteretsu.kayac.com/2009/12/android-12.php

tm.getSimOperator() | us310260
tm.getSimOperatorName() | Android
tm.getDeviceId() | 0
tm.getDeviceSoftwareVersion() | null
tm.getLine1Number() | 15555218135
tm.getNetworkCountryIso() | us
tm.getNetworkOperator() | 310260
tm.getNetworkOperatorName() | Android
tm.getSimSerialNumber() | 8.90141E+19
tm.getSubscriberId() | 3.1026E+14
tm.getVoiceMailAlphaTag() | Voicemail
tm.getVoiceMailNumber() | 15552175049

Build.VERSION.RELEASE | 1.6
Build.VERSION.INCREMENTAL | 20842
Build.VERSION.CODENAME | REL
Build.VERSION.SDK_INT | 4
Build.VERSION.SDK | 4

メインのスレッド以外から、UIを操作する方法

要点:
ハンドラにてhandleMessage(Message m)をOverrideし、
その中に、UIパーツを操作する処理を記述する。


例では、mBodyというLinearLayout上に、TextViewとSurfaceViewを配置しています。
SurfaceViewでは、スレッドを回して描画し続ける感じで組んでます(ゲームアプリのアレ)


例:
SurfaceViewを継承したクラス。スレッドの設定時に
handleMessageをOverrideして、UIパーツに対してやりたい事を書きます。
今回は、TextViewに"hogehoge"という文字列を設定させます。

	/*
	 *省略してるけど、MyThreadのメンバにhandlerがあり、コンストラクタで設定するようにしてる。
	 * この辺は別に人それぞれ。
	 */
	mTread = new MyThread(holder, context, new Handler() {
        	@Override
        	public void handleMessage(Message m) {
			// TextViewにテキストを設定する
        		mBody.getTextView().setText(m.getData().getString("hoge"));
        	}
        });


MyThreadというThreadを継承したもの(別スレッド)から呼び出す場合は、
メッセージを送信して、さっきのhandleMessage関数を呼び出してUIへの操作を行う。

例:

	Message msg = mThread.getHandler().obtainMessage();
	Bundle b = new Bundle();
	b.putString("hoge", "hogehoge");
	msg.setData(b);
	mThread.getHandler().sendMessage(msg);    


これをしないと、メインのスレッド以外から操作しちゃダメよーという例外が
発生してアプリが落ちる。

GestureDetector.OnDoubleTapListener, GestureDetector.OnGestureListener

GestureDetector.OnDoubleTapListenerと
GestureDetector.OnGestureListenerを実装したクラスで、
画面をタップした時の呼ばれるイベント順番メモ

'10/07/01追記
テスト中不可解な動きをしたので、調査した結果、ドラッグさせた際の挙動が2種類あるようでしたので、追記しました。

ちょい押し
     onDown -> onShowPress -> onSingleTapUp -> onSingleTapConfirmed

長押し
     onDown -> onShowPress -> onLongPress

おす→ドラッグ→普通に離す
     onDown -> onShowPress -> onScroll *n
     '10/07/01追記
     画面を押した瞬間スクロールさせた場合、onShowPressが省略されて、onDown -> onScrollと呼ばれるようです。

おす→ドラッグ→ぱっと離す(フリック)
     onDown -> onShowPress -> onScroll *n -> onFling
     '10/07/01追記
     画面を押した瞬間スクロールさせた場合、onShowPressが省略されて、onDown -> onScrollと呼ばれるようです。

ダブルタップ
     onDown -> onShowPress -> onSingleTapUp -> onDoubleTap -> onDoubleTapEvent


シングルタップとダブルタップが競合しそうだから、
シングルタップのイベント処理は、onSingleTapConfirmedに書いた方がいい感じ。

続・SurfaceViewの描画メソッドについて

やっと解決しました・・・ 良かれと思ってやってたことが・・・

SurfaceViewのコンストラクタ内で、

    // 背景を灰色にする
    setBackgroundColor(R.color.metal);

というコードを記述していたことが問題でした。

これは画像をマウスでグリグリしてるときに、まだ読み込みが完了していない部分を灰色で表示できたらいいなーと思って加えていたコードです。
実際は、予めcanvas全体を前述の目的の色で塗りつぶしてから、読み込み完了している画像を描画→読み込みスレッドが完了したらその部分を再描画ということで対応していましたので、全くもって不要・・・!

不要な上に足まで引っ張ってくれるとは・・・・(´・ω・`)

さくっと削除して、画面が薄暗くなる状態を脱出しました。

一発目のポストからこんな恥ずかしいことしてたなんて・・・ああああ

overrideした関数(onDrawやdraw)はUIメインのcanvasに対して描画するから、onDrawとかを使うと明るく表示されてたのかな。
んで、独立した関数で描画すると、setBackgroundColorで設定した薄暗い色の背景に描画してたんで全体的に薄暗くなってたと・・・。

こんなふうに解釈しました。

同じようなミスする人は居ないとは思いますが、誰かの参考になればいいな。。。。

bookmark memo

Androidで長押し(ロングタップ)やダブルタップのイベントを取得するサンプル
http://www.hoge256.net/2009/09/462.html

AndroidSQLiteのDB操作をするための基礎知識
http://www.atmarkit.co.jp/fjava/rensai4/android06/android06_1.html

android hacking 2日目
http://veritas-vos-liberabit.com/note_on/2010/02/android-hacking2.html

SurfaceViewについて
http://d.hatena.ne.jp/ytksn/20090417/1239982918

SurfaceViewの描画メソッドについて


大きな画像を分割してcanvasに貼りつけて表示をし、マウスでぐりぐりするアプリを開発中。
Viewで実装したが割とカクカクするんで、高速化を求めてSurfaceViewを採用してみた。

なんとか動きましたよレベルのものは作れたが、不具合が・・・
この問題さえ回避できれば、速度向上ができたし問題ないんだけどなぁ。

その不具合というのが、アプリを起動して画像が表示されるが何か暗い。
省エネモードに入った感じの暗さで表示される・・・・ why?

    /**
     * アプリケーションが呼び出す描画関数
     */
    public void hogeDraw() {
        Canvas canvas = getHolder().lockCanvas();
        if (canvas != null) {
            try {
                xDraw(canvas);
            } finally {
                getHolder().unlockCanvasAndPost(canvas);
            }
        } else {
            Log.i("fastDraw", "couldnt get canvas");
        }
    }

xDrawで実際に描画。
これだと予定した動作はするんだけど、前述通り暗い。何故か暗い。

あと、発見したことだけど
xDraw(canvas)のところを、overrideした関数(onDrawとかdrawとか)で実装すると、2回目以降に呼ばれたときにgetHolder().lockCanvas()からcanvasが取れなくなる。
何故か取れなくなる。

そもそもそんなもん呼ぶなよって思われそうだけど、知識がないからいろいろ試すしか・・・w


SurfaceViewのcanvasと、メインのcanvasは別物という記述を見たことがあるけど、そのへんが影響してるのかなー・・・。
ただし、これでやると前述の暗いってのが解消されるんだよなぁ・・・。
だけど、2回目以降canvasが取れなくなるからグリグリができなくなる。
起動して表示してハイおしまい!という誰得アプリに・・・

とりあえず、なんで暗くなるのか調べないと!