[titanium] regionChangedの抑制

Titanium™ Advent Calendar 2013 – Adventar の7日目は、大さん橋を見ながら@mogyaがお送りします。

1466042_10152052877289243_273095704_n.jpg

山下公園でコード書くとかかっこよくない?と思ったんだけど、寒くてコードどころじゃない感じでした…

さてさて、TitaniumにはMapViewというのがあって、これを使うと簡単に地図アプリが作れるのですが、GoogleMapsSDKのバージョンが上がった関係で、現在Androidでは標準のMapViewではなくてModules.Mapを使うように言われていて、ちょっと混乱期にあります。3.2.0で旧バージョンが削除されるらしいので、来年には落ち着くんじゃないかと思うのですけど。現行だと、こんなかんじで書かないといけません。

map_view.js

さらにさらに、MapViewを使って、地図をドラッグした時に発生するregionChangedイベント(これも最近名前がregionchangedイベントに変わりましたw)を契機としてモバイラーズオアシスAPIを呼び出すようにすれば、電源が使えるお店を一覧するアプリを作ることが出来ます。

実際作ってみるとわかるのですが、このつくりだと微妙に使い勝手の悪いアプリになります。ちょっと離れた位置を見ようとして移動を繰り返すと、画面がちょっと動くたびにデータをロードしに行くので、処理がたまってだんだん重くなってしまうのです。

ブラウザ上のGoogleMapsSDKで開発する場合には、処理が落ち着いた時に呼び出してくれるidleイベントというのが存在するので、これを使えば綺麗に実装することが出来ます。

[GoogleMapsAPI] APIと組み合わせる時のイベントはidleを使う – もぎゃろぐ

で、idleイベントが存在しないAndroidやiOSのSDKでどうするか、というのがこの記事のテーマです(前置き長すぎだろうw)

idleイベントと近そうなイベントとして、completeイベントというのがあって、これを使うのも一つのアイデアです。ただこのイベントは、地図のロードが完全に終わってから呼び出されるので、これで実装すると、「ユーザーがドラッグ→地図がロードされる→(一呼吸)→店舗が表示される」という、これまた使い勝手の微妙なアプリになります。スポット数が少なかったり、通信環境が安定していてAPIが高速に応答してくれていれば、余りばれないのですけど・・・

今年リリースした電源検索新バージョンや、iPhone版の電源検索では、regionChangedイベントでそのままAPIを呼び出さずに、キューにイベント情報を積んでおいて、一定時間regionChangedイベントが発生しなくなったら、最後の一回分だけAPIを呼び出す、という実装を行いました。

data_task.js

data_task.js部分が問題のロジックをカプセル化したものです。
regionChangeイベントが発生したらとりあえず全部requestでDataTaskにあずけてしまいます。

mapview.addEventListener(regionchanged,function(evt){
datatask.request(evt);
});

DataTaskは内部でタイマーを持っていて、一定時間が経つと、最後に呼び出したrequestの引数を使って、actionコールバックを呼び出します。

actionコールバックの中でAPI呼び出しを行うようにすれば、おおむね、ユーザーが地図をドラッグしおわったタイミングでAPI呼び出しを行うことが出来ます。

var taskAction = function(self,evt){
Titanium.API.info('taskAction '+evt.longitude+','+evt.latitude);
};
var DataTask = require('data_task');
var datatask = new DataTask({
interval:3000,
action:taskAction,
caller:this
});
datatask.start();

Dalvik_Debug_Monitor.png

書きながら「そこまで頑張る必要があったんだろうか。実はcompleteイベントでいいんだったりして」とちょっと不安になってきたのですけど・・・大丈夫なはずだ。神は細部に宿る!

明日はryugooさん@ChatWorkです。よろしくお願いしますー。