« IMoNi よくある質問(FAQ) | メイン | IMoNi 1.4.2で受信できなかった方へ »

落ちないServiceの作り方

 最近このBLOGがIMoNiのサポートサイトと化しているので、たまには開発者向けの投稿でも書いてみようと思います。

 何らかを定期的に監視し続けるときのように、ずっと動き続けるService(システムが提供する機能というわけではなく、Androidの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はまっさらな状態なので、以前の最新の状況を読み込んで、何をやっていたかを思い出してから再度動き続けるようにします。

以上です。
繰り返しますが、他にも「おれはこうやってる」などのアイディアや観点があれば是非教えて貰えるとうれしいです。

トラックバック

このエントリーのトラックバックURL:
http://www.grandnature.net/bin/mt-tb.cgi/149

コメント (11)

kaa:

同じような問題でいろいろ試しましたがalarmmanagerが一番落ちにくかったですね
スレッドよりしぶとく生き残ってくれる感じ。リピート間隔の誤差はでますがぶれる前提で考える方向で。
あとはonDestroyがないとかもあったので、どうしてもダメな時は綺麗に終了することを目指すって方針にしました。
キャンセル一式して通知だしたり。アプリいくつかインストールして負荷かけてみたりするとさすがに動作厳しいので。
ほんと長時間バックグラウンド起動アプリは検証時間が他の数倍いきますね。

もも9:

お世話になってます。
HT-03Aのバージョンアップにより、IMoNiのウィジェットの体裁が少し壊れてしまいました。状態確認のランプは見えないようになってしまっています。
ご確認頂ければ幸いです。

失礼します。

egg:

kaaさん

ありがとうございます!そうですね、キレイに終了しないとだめですね。やはり検証に時間をかけられているとのことで、自分だけじゃないことがわかって少し安心しました。

もも9さん

最新のバージョン1.4.1にアップデートして頂ければ、直っていると思います。もしそれでも直らないようでしたら、一度ウィジェットを消して、再度配置し直して頂けないでしょうか

もも9:

1.4.1で解決しました。ありがとうございました。

『画像も含めて本文を表示』を使うと、文字化けが起きてしまうのですが、コレもファームが1.6になったせいでしょうか??時期は合います。

kj:

1.4.2受信不可

tnx-01:

いつもIMONIにお世話になっています。

今朝、1.4.2にアップしたところ受信不良の状態になってしまいました。
AppManagerでバックアップしてあった1.4.1にもどしたところ問題なく動いていますので、1.4.2の問題だと思われます。

ご確認をいただければ幸いです。

tnx-01:

何回もすみません・・・

1.4.2ですが、ストアから1.4.1に直接アップデートすると動きませんが、1.4.1をアンインストールしてから新規にストアからインストールすると動くようになりました。
ご報告まで・・・


kj:

1.4.2新規インストールで受信可

egg:

tnx-01さん,kjさん

eggです。ご迷惑をおかけしました。先ほど修正版をアップしました。どうもすみません。

もも9さん

1.4.1までは、1.6だと文字化けしています。1.4.2で対応しました。最新版の1.6.3をお使い下さいませ

tnx-01:

いつもながら素早い対応ありがとうございます。
IMONIがないと困るので、本当にありがたいです。

これからもよろしくお願いいたします。

hiro:

お世話になります。

HT-03Aでimoniを使用させていただいております、本当に助かります。

質問と言うか要望ですがメールのチエック間隔ですが最低の3分にセットして使用させていただいておりますがもう少し時間を短くはできないでしょうか?

お手数掛けて申し訳ありません。

コメントを投稿

About

2009年10月23日 20:07に投稿されたエントリーのページです。

ひとつ前の投稿は「IMoNi よくある質問(FAQ)」です。

次の投稿は「IMoNi 1.4.2で受信できなかった方へ」です。

他にも多くのエントリーがあります。メインページアーカイブページも見てください。