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 のソレも色々確認してみたいですが。