2011年11月22日火曜日

強制終了を考慮したServiceの設計

#更新予定とか書いといて、結局一ヶ月が経ちました

以前書いたとおり、Serviceは強制終了させられます。(要因などはこちらのエントリーで)
ではどうするか、ということですが、まずはAndroidのDevelopers Guide。
Services | Android Developers  (こちらで日本語に訳されてます)

The Basicsの最後の方を見ると、以下のように書いてます。(日本語サイトですとAndroid システムはメモリが少なくなり・・・のくだり

The Android system will force-stop a service only when memory is low and it must recover system resources for the activity that has user focus. If the service is bound to an activity that has user focus, then it's less likely to be killed, and if the service is declared to run in the foreground (discussed later), then it will almost never be killed. Otherwise, if the service was started and is long-running, then the system will lower its position in the list of background tasks over time and the service will become highly susceptible to killing—if your service is started, then you must design it to gracefully handle restarts by the system. If the system kills your service, it restarts it as soon as resources become available again (though this also depends on the value you return from onStartCommand(), as discussed later). For more information about when the system might destroy a service, see the Processes and Threading document.

 ポイントは以下:

  1. 長時間Serviceを起動してると、システムに強制終了させられやすくなる
  2. 自分のServiceが強制終了させられても、SystemがServiceを再起動してくれる。
  3. onStartCommand()実行後、戻り値を何にするかで再起動の挙動が変わる。

3がポイントですが、onStartCommand()で特定の戻り値を設定することで、再起動時に、最後にServiceに飛んで来たIntentを再配信することが出来ます。(戻り値に何を設定するかはAPI仕様書や、上記のServiceのDeveloper guideを参照)

つまり、強制終了されてもいいように作るには、
  1. ServiceはIntentによるイベントドリブンな形で作る
  2. ServiceがIntentを受けたら、そこからの一連の処理は受けたIntentで一意に決まるようにする

こうしておけば強制終了されてもIntentが再配信されるので、そのIntentを受けて処理を再開できます。
処理もIntentの種別やデータで一意に決まるので、復帰も問題ないです。

もちろん、Serviceは連続的に動かすものなので、状態を持たせたりして、一意に決められない場合もあります。というか、こっちの方が当たり前のような。

今回試した方法では、Serviceの状態変数(State patternとか使ったらClass)や、保持しているデータをIntentを受けるたびにファイルシステムに書き出すようにしました。
Intentを受けるたびに、読み出しをすることで、再起動後も状態とデータを保持できます。

この方法ですと、副次的なメリットもあって、Low batteryでの強制終了や電池パックがはずれて・・・みたいなときでも、復帰が出来るようになります。もちろん、状態保存中に電池が外れて、みたいなパターンのフォローは必要ですが。

デメリットは、毎回ファイルシステムにアクセスするので、電池を食うのと、処理が重くなること。このあたりは、読み出し・書き出しをたとえば3回に一回にするとか、読み出しも再起動時のみ、にするなどの対策をすれば良いかと。

とりあえず、この方法で、しばらく評価してますが、問題はなさそうです。

0 件のコメント:

コメントを投稿