MyTracks 読み (15)
いきなりシリーズ再開。てーか、調べものがあった止むを得ず、という所があったりなかったり。ちょっと版数古いかもしれませんが、そのあたりは勘弁して下さい。
始点
MyTracks の onOptionsItemSelected メソドより。
@Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case MyTracksConstants.MENU_START_RECORDING: { startRecording(); return true; }
MyTracks#startRecording メソドの定義は以下か。
/** * Starts the track recording service (if not already running) and binds to * it. Starts recording a new track. */ private void startRecording() { if (trackRecordingService == null) { startNewTrackRequested = true; Intent startIntent = new Intent(this, TrackRecordingService.class); startService(startIntent); tryBindTrackRecordingService(); } else { try { recordingTrackId = trackRecordingService.startNewTrack(); Toast.makeText(this, getString(R.string.status_now_recording), Toast.LENGTH_SHORT).show(); setSelectedAndRecordingTrack(recordingTrackId, recordingTrackId); } catch (RemoteException e) { Toast.makeText(this, getString(R.string.error_unable_to_start_recording), Toast.LENGTH_SHORT).show(); Log.e(MyTracksConstants.TAG, "Failed to start track recording service", e); } } }
trackRecordingService が動いてるかどうかで動作が異なってます。動いてなければ開始させるし、動いてれば新しい id で云々なのかな。
まず Service が開始されてないケイスですが、Intent 作って startService してます。その後に呼ばれてる tryBindTrackRecordingService メソドですが定義が以下。
/** * Binds to track recording service if it is running. */ private void tryBindTrackRecordingService() { Log.d(MyTracksConstants.TAG, "MyTracks: Trying to bind to track recording service..."); bindService(new Intent(this, TrackRecordingService.class), serviceConnection, 0); }
これ、何故に同じ Intent をもっかい作ってるのかが謎。あと serviceConnection ですが定義が以下かな。引用するには長いな。とりあえず
- trackRecordingService に参照ぶち込む
- TrackRecordingService の内部クラス ITrackRecordingService.Stub の参照
- ちょっとこの IDL 云々が弱い
- 新しい track 作って云々
という事で setSelectedAndRecordingTrack メソドですが SharedPreferences なナニに recordingTrackId を put しております。何故に SELECTED_TRACK と RECORDING_TRACK という形で二つ持ってるのかは謎ですが。
ちょっと脱線
AIDL 云々について。
- MyTracks のケイスであれば ITrackRecordingService.aidl で interface を定義
- プロジェクトの build 時に ITrackRecordingService.java が自動生成
- Service の中で private な ITrackRecordingService.Stub な無名クラスを作って new したソレを定義
- onBind では上記で定義されたオブジェクトを戻せばよい
KitchenTimerService 方式よりはこっちのが楽なのかどうなのか。
閑話休題
基本的にトラック記録な処理って ITrackRecordingService#startNewTrack になるのか。ポイントを以下に控え。
- Track ってクラスについて
- MyTracksProviderUtilsImpl#insertTrack メソドについて
- trackId 取得のためだけにあるのかな
- MyTracksProviderUtilsImpl#updateTrack メソドについて
- PeriodicTaskExecuter クラスについて
- 以前のエントリで確認入ってたりするんだろなorz
末端らへんのメソドについても確認必要。以下なあたり。
stats = new TripStatistics(track.getStartTime()); if (announcementFrequency != -1 && executer != null) { executer.scheduleTask(announcementFrequency * 60000); } length = 0; showNotification(); registerLocationListener(); splitManager.restore(); signalManager.restore(); return trackId;
でわ、以下で順に確認をば。
MyTracksProviderUtilsImpl#insertTrack メソドについて
ええと、定義が以下です。
@Override public Uri insertTrack(Track track) { Log.d(MyTracksProvider.TAG, "MyTracksProviderUtilsImpl.insertTrack"); return context.getContentResolver().insert(TracksColumns.CONTENT_URI, createContentValues(track)); }
ContentResolver だ。ちなみに createContentValues っていくつか overload されてますね。ただ、Track な引数を受け取る createContentValues メソドは locations な属性は相手にしていないように見えます。
MyTracksProviderUtilsImpl#updateTrack メソドについて
ええと、、定義が以下。
@Override public void updateTrack(Track track) { Log.d(MyTracksProvider.TAG, "MyTracksProviderUtilsImpl.updateTrack"); context.getContentResolver().update(TracksColumns.CONTENT_URI, createContentValues(track), "_id=" + track.getId(), null); }
どうやって id 特定してるのか、って思ったら
- MyTracksProviderUtilsImpl#insertTrack でケツに id が付いた URI が戻る
- Uri#getLastPathSegment() でケツの id 取得して trackId に保存
- Track#setId で id セットして update
てーコトは、以下なシーケンスはそれなりに使い回しが可能なんかな。
Uri trackUri = providerUtils.insertTrack(track); long trackId = Long.parseLong(trackUri.getLastPathSegment()); track.setId(trackId); track.setName(String.format(getString(R.string.new_track), trackId)); providerUtils.updateTrack(track);
うーん、素晴しい。
PeriodicTaskExecuter クラスについて
以前のエントリによると一定時間おきに何かをするソレ、という記述があります。根拠が不明なあたりが超微妙。
ってこれ、自分で定義してるんですね。で、PeriodicTaskExecuter とか PeriodicTask とかの中身を見てみても具体的な記述が全く無い状態だったので、TrackRecordingService の onCreate の中身を見たら以下な記述を発見。
if (mTTSAvailable && (announcementFrequency != -1)) { if (executer == null) { SafeStatusAnnouncerTask announcer = new SafeStatusAnnouncerTask(this); executer = new PeriodicTaskExecuter(announcer, this); } }
む、SafeStatusAnnouncerTask は PeriodicTask を実装しとりますな。ここに具体的なソレが書いてあるに違いない。と思ったらこいつも wrapper だったス。これって何かのパターンなのかなぁ。
ここで一旦手を止めます。多分帰宅後に見るのは C2DM のはず。beagleboard のソレも色々確認してみたいですが。