2011年9月25日日曜日

[Android]EditTextに入力中の文字列を、リアルタイムでどんどんジオコーディングしてみる

さて。お仕事上MapViewと格闘することが最近多いので、今日もそんなMapView関連の話題を一つ。

MapViewでなにかの場所を選んでもらう時に、ユーザーに緯度経度をいきなり入力させるようなケースってマズ無いですよね。だいたいは特定の位置から始まるか、GPSなんかから現在位置を取得してそれを地図の中心にしたりです。でも、使い方によってはさらにもう一歩踏み込んだ動作をしてくれるとうれしい。そう、たとえば住所を入力したらそこを中心に表示してくれるとか、「東京タワー」とか「上野駅」とか「那須ハイランドパーク」「沼田ドイツ村」あたりでもその施設にぴょんと飛んでくれるとすっげぇうれしいですよね?今日はそれをかっこ良くキメる方法の話。
そんな動きをするには大きく分けて3つの動きが必要です。
・入力中や入力済みの文字列を自動で取得する
・文字列から位置情報を取得する
・位置情報を指定してそこを中心にMapViewを表示する

そんなわけで、こいつらを順番に解説・紹介していきたいと思います。
まずは一つ目、「入力中や入力済みの文字列を自動で取得する」

この動作にはEditTextの持つ「addTextChangedListener」と、Handlerを使用します。
個人的に、並列処理や別スレッドでのGUI操作はHandlerではなくてAsyncTask推奨派なんだけど、今回は実装が単純なので、記述量が減らせるHandlerを選択。そう、簡単なんですよ!これ!

addTextChangedListenerというのは、(実際にはTextViewのメソッドだが)EditTextで変更があった場合に、「変更が行われた事」を通知するListenerを設定する事ができます。
これを利用して、EditTextに変更があるたびにメソッドを呼び出せるので、「入力中や入力済みの文字列を自動で取得する」ことができるわけなんです。ではなぜHandlerも使用するのか?答えは処理を送らせるため。これは実はこの後の動作である「文字列から位置情報を取得する」というのは、瞬時に終わるような処理ではないから。キーワード補完などならともかく、位置情報は入力途中の状態を常に絞り込み続ける必要もないですよね?ましてや「東京タ」まで入力した次点で、「ワー」を打ち込んでる最中に位置情報を検索する事で誰が得をするでしょう?しません。しかもこの処理が重いと入力すらもたついて非常にストレス!よって、Handlerで処理を遅延させて、かつ処理の回数自体を減らします。

まずはソースコードをどうぞ。


さて、まずはaddTextChangedListenerによりリスナーを設定します。ここではリスナーは自分自身として、そのままこのクラスにメソッドを追加しています。そのために今回ActivityクラスにTextWatcherをimplementsしています。
onTextChangedでは呼ばれる回数がなんとなく不安定でかつ無駄に呼ばれてるようなので、ここではafterTextChangedメソッドに処理を記述しています。もっとも、ここではHandlerを設定しているだけです。このとき、Handlerを削除する処理を入れる事で、連続でHandlerが設定された場合には一番最後に設定されたものだけが実行されます。ここでの実行時間は1秒後になっているので、つまり「最終入力から1秒後」にのみ処理が行われます。1秒以内の間隔で入力していれば処理は行われませんし、1秒未満の間隔で処理される事も無いので、入力に比較的影響を与えないで処理できます。(スペックに依存しそうですが。)
sendEmptyMessageDelayedで送られたメッセージは、HandlerのdispatchMessageメソッドを呼び出します。ここで、そのメッセージがなんであるかを判定し、間違いなく入力後の処理のために呼び出されたHandlerだった場合にのみ、ジオコーディングを行う、というコードになっています。
これはどのメッセージかの識別につかっている、という事ですね。ここでは一個しか無いので不要に思われるかもしれませんが、他のメッセージが飛んでこない保証もないので、しっかりくっきり区別しておきましょう。

さて、次は「文字列から位置情報を取得する」、ジオコーディングの方法です。
[Android]EditTextに入力中の文字列を、リアルタイムでどんどんジオコーディングしてみる2
追記 10/4 書きました。
[Android]EditTextに入力中の文字列を、リアルタイムでどんどんジオコーディングしてみる3

0 件のコメント:

コメントを投稿