ページ

2011年11月10日木曜日

onStartCommandとその戻値について

onStartCommandとその戻値について

副題:鳩ポッポは永遠に

問題
私が現在開発中のプログラムで、Serviceがnull pointer errorを引き起こす。
Activityで作成した画面で「戻る」コマンドを実行したり、EclipseのDebugのTerminate and Removeコマンドを実行すると、Serviceがヌルポするのである。
この原因が明確になるまでは「データベースのCursorをcloseしていないです」という、全く根拠の無いエラーメッセージが出ていたため、問題解決には時間を要した。

原因
ServiceのonStartメソッドのIntent引数を使って、ある種の処理をしていたため、上記問題が発生した。
何も対策を講じていない場合であって、プロセスが強制終了した場合、ServiceのonStartメソッド又はonStartCommandメソッドが再起動してくる。そして、そのメソッドの第一番目のIntentの引数の内容はnullになっているのである。
私が開発中のプログラムでは、onStartメソッドの第一番目の引数の(nullが代入された)Intent変数を使おうとしたため、errorになった。

再現性
実験的に作ったサンプルプログラムでは、「戻る」コマンドを実行した程度では、このような現象は発生しない。
この問題をサンプルプログラムで再現するには、DDMSのStop Processを使って、プロセスを強制終了させれば良い。そうすれば、しばらく経つと、Serviceが起動してくる。
onStartメソッド又はonStartCommandメソッドを実行してしまったServiceで、この問題は発生する。
bindServiceメソッドだけを使って生成したServiceでは、(onStartメソッド又はonStartCommandメソッドは実行されないので)このような問題は発生しない。

考察
こんなのが仕様なのだろうか。バグじゃないのか?こんな変な振る舞いが仕様である訳がない。
と、思ってしまうが、仕様であるらしい。なぜならば、このような仕様こそが、♪背景音楽再生向きなのじゃ~♪、とServiceの記事に書かれている。
This mode makes sense for things that will be explicitly started and stopped to run for arbitrary periods of time, such as a service performing background music playback.
このような仕様は、background musicには良いとされているが、foreground musicには向いていない。プロセスが生成されて再起動してくるのである。再起動した後には、音楽の先頭から演奏が始まるのだ。
ごく限られたニーズにしか対応していないように感じてしまうのは、果たして私だけだろうか。
次の中から選んでください。
  1. background music用に作成した仕様なので問題は無い。
  2. ここまで巧妙に作ってあるのだから、バグである訳が無い。
  3. ニーズが少ない仕様に感じられるので、もっと多彩な活用事例を紹介して欲しい。
  4. onStartCommandメソッドの戻値の在り方を学習しなければならないのが面倒である。自分のアプリと関係無いことに付き合わされる。
  5. 本当はバグです。
  6. むむむ!

対策
同様のお悩みを持った御仁のサイトは次のとおりである。
Android: Serviceがヌルポで落ちる
このサイトに対応策が書かれています。
この記事に触発されて、onStartCommandメソッドの戻値についてServiceの記事を読みました。しかし、Serviceの記事は意味不明な内容でした。このため、簡単なプログラムを作成し実験してみた。

onStartCommandメソッドの戻値として次を3個のどれかを使えば良い。
START_STICKY_COMPATIBILITY
START_NOT_STICKY
START_REDELIVER_INTENT

START_STICKY_COMPATIBILITYを使えば、再起動してきません。再起動しないのが、本来の在り方だと思いますので、これを使うのが良いでしょう。

START_REDELIVER_INTENTを使えば、初回起動時と同じ値が入ってきます。しかも、START_FLAG_REDELIVERYを活用すれば、初回起動時と再起動時との見分けができます。

もし、START_STICKYを使う場合には、又はonStartメソッドを使う場合には、Intent引数がnullである場合への対策を講じれば良い。

START_CONTINUATION_MASKは、何のためにあるのかわかりません。Maskを施す必要性がどこにあるのでしょうか。

Serviceを実装し、そのonStartCommandメソッドの引数を使っているアプリは、テスト工程に次の作業を追加しなければならない。

  • アプリを強制終了した場合における、その後のServiceの振る舞い。


詳細
詳細は、同名の別サイトonStartCommandとその戻値についてに書いておきました。

0 件のコメント:

コメントを投稿