落ちないServiceについて

2,386 views
Skip to first unread message

egg

unread,
Oct 23, 2009, 7:45:33 AM10/23/09
to android-...@googlegroups.com
江川です。
何らかを定期的に監視し続ける、といった、ずっと動き続けるServiceを作ることが
あると思いますが、私が初めて取り組んだときは、簡単なようで意外とハマりどころが
あるなと思いました。このことは、いつの間にか落ちていたり、停止できなかったり
するアプリを目にする機会が意外と多いことからも頷けると思います。

 多分いろいろな実装方法があると思いますし、処理の特性によって最適な方法は
異なるかもしれませんが、私が一番簡単じゃないかなと思っている方法を述べます。
デベロッパーの方、情報交換させてくれませんか。
「おれ(わたしは)こうやってる」などのアイディアや「こうした方がいいんじゃないか」
といった観点があれば是非教えて貰えるとうれしいです。

・息の長いThreadよりonStartとAlarmManagerを使う
 どちらも試しましたが、後者の方がコードが簡潔になりますし、バグが混入しに
くいような気がします

・onStartから作業用Thread(Task)を起こす
 onStartで時間をかけすぎると(多分5秒以上)怒られるので、時間がかかる場合
は別スレッドで行い、onStartは直ちに終わるようにしています。ちなみに生Thread
よりもjava.util.concurrent.ExecutorServiceなどを使ったほうが簡単かもしれません。
例外の取り方に癖があるので気をつけます。
http://java.sun.com/javase/ja/6/docs/ja/api/java/util/concurrent/Callable.html

・定期的に処理を行う場合は、作業用Threadの処理終了時にAlarmをset
 作業用Threadは、一回処理をして終わるようにします。定期的に処理したい場合は
Threadが終わる時にAlarmに登録します。

・止める処理もonStart
 止めるときの処理もonStartでやるのがいいような気がします。intentのActionで
振舞いを分けるイメージです。以下のような感じです。止める時も呼び側がstartServiceメソッド
になってしまうのが少し誤解を招きそうですが、僕はこうしています。

public void onStart(final Intent intent, int startId) {
 super.onStart(intent, startId);
  if (ACTION_EXECUTE.equals(intent.getAction())) {
   // スレッド起こして処理実行
  }
  else if (ACTION_STOP.equals(intent.getAction()) ){
   // 終了処理(Alarmのキャンセルなど)
  }
  ・・・
}
もちろんバインドして終了処理を呼ぶ方法もありだと思います。

・必要に応じてwakelockを使う
 Alarmはpartial wakelockを取得してないとスリープ時に呼ばれないことがあるようです。
またwifiなどもスリープする可能性があるので、処理の特性に応じて適宜最小限の
wakelockをかけます。


・・・ところで、Androidにはちょっと厄介な特性があります。それは、メモリが
足りないなどの諸々の理由でServiceが勝手に殺されることがあるということです。

・onLowMemoryは期待しない
 メモリが少なくなるとonLowMemoryメソッドが呼ばれます。このメソッドをうまく
活用すればよいのですが、あまり役に立ちません。なぜなら、このメソッドは
ちょっとしたことですぐに呼ばれるからです。

・onDestroyも期待しない
 じゃ、死ぬときにonDestroyが呼ばれると思いきや、呼ばれずに死ぬことの方が
多いです。なので、ここにコードを書いてもあまり意味はありません。

・各処理の終了時に現在の状況を保存しておき、onCreateで再startする
 つまり死ぬことを予め予期できないし検知できないので、いつ死んでもいいように、
なんらかの処理を終えたときに最新の状況を逐次記録(永続化)しておきます。
Serviceのプロセスは殺されたとしても、しばらくするとまた別のプロセスが勝手に
生成されます。しかしこの時点ではServiceはまっさらな状態なので、以前の最新の
状況を読み込んで、何をやっていたかを思い出してから再度動き続けるようにします。

以上です。
繰り返しますが、他にもアイディアや観点があれば是非教えて貰えるとうれしいです。

------------------------------------------
EGAWA Takashi

nagamatu

unread,
Oct 23, 2009, 9:31:35 AM10/23/09
to Android-SDK-Japan
他のアイディア:

Service.setForeground(true)を呼び出す事で、Backgoundサービスではなく
foregroundにしてしまう。皆がこれを行うと、問題でしょうけどね。

http://developer.android.com/reference/android/app/Service.html#setForeground(boolean)

You can set this flag if killing your service would be disruptive
to the user.

--
ながまつ


On 10月23日, 午後8:45, egg <t.eg...@gmail.com> wrote:
> 江川です。
> 何らかを定期的に監視し続ける、といった、ずっと動き続けるServiceを作ることが
> あると思いますが、私が初めて取り組んだときは、簡単なようで意外とハマりどころが
> あるなと思いました。このことは、いつの間にか落ちていたり、停止できなかったり
> するアプリを目にする機会が意外と多いことからも頷けると思います。
>
>  多分いろいろな実装方法があると思いますし、処理の特性によって最適な方法は
> 異なるかもしれませんが、私が一番簡単じゃないかなと思っている方法を述べます。
> デベロッパーの方、情報交換させてくれませんか。
> 「おれ(わたしは)こうやってる」などのアイディアや「こうした方がいいんじゃないか」
> といった観点があれば是非教えて貰えるとうれしいです。
>
> ・息の長いThreadよりonStartとAlarmManagerを使う
>  どちらも試しましたが、後者の方がコードが簡潔になりますし、バグが混入しに
> くいような気がします
>
> ・onStartから作業用Thread(Task)を起こす
>  onStartで時間をかけすぎると(多分5秒以上)怒られるので、時間がかかる場合
> は別スレッドで行い、onStartは直ちに終わるようにしています。ちなみに生Thread
> よりもjava.util.concurrent.ExecutorServiceなどを使ったほうが簡単かもしれません。
> 例外の取り方に癖があるので気をつけます。
> (http://java.sun.com/javase/ja/6/docs/ja/api/java/util/concurrent/Call...

egg

unread,
Oct 24, 2009, 2:53:54 AM10/24/09
to android-...@googlegroups.com
ながまつさん

リプライありがとうございます。

> Service.setForeground(true)を呼び出す事で、Backgoundサービスではなく
> foregroundにしてしまう。皆がこれを行うと、問題でしょうけどね。

あ、ホントですね。携帯電話だと心配になりますが
用途が限定された端末ならかなり有用ですね。
ありがとうございます!

------------------------------------------
EGAWA Takashi



2009年10月23日22:31 nagamatu <naga...@gmail.com>:

Jyunji.jag

unread,
Oct 27, 2009, 7:20:00 PM10/27/09
to Android-SDK-Japan
just FYIですが、2.0でこのあたりちょっと変わったみたいですね。

http://developer.android.com/intl/ja/sdk/android-2.0.html

New Service APIs to help applications correctly handle Service life-
cycle, in particular low memory situations where a Service may be
killed while it is running.

* Service.setForeground() has been deprecated and now effectively
performs no operation. This is replaced with a new API, startForeground
(), that helps (and requires) associating an ongoing notification with
the foreground state.

近藤

On Oct 24, 3:53 pm, egg <t.eg...@gmail.com> wrote:
> ながまつさん
>
> リプライありがとうございます。
>
> > Service.setForeground(true)を呼び出す事で、Backgoundサービスではなく
> > foregroundにしてしまう。皆がこれを行うと、問題でしょうけどね。
>
> あ、ホントですね。携帯電話だと心配になりますが
> 用途が限定された端末ならかなり有用ですね。
> ありがとうございます!
>
> ------------------------------------------
> EGAWA Takashi
>
> 2009年10月23日22:31 nagamatu <nagam...@gmail.com>:
>
>
>
> > 他のアイディア:
>
> > Service.setForeground(true)を呼び出す事で、Backgoundサービスではなく
> > foregroundにしてしまう。皆がこれを行うと、問題でしょうけどね。
>
> >http://developer.android.com/reference/android/app/Service.html#setFo...)
Reply all
Reply to author
Forward
0 new messages