ページ

2014/03/19

[Android]Serviceを停止されても自動的に再起動して常駐させる

ユーザーに嫌われる常駐 Service の作り方。
Service が停止されるタイミングはいくつかあるので
その全てで Service を再起動するようにすれば常駐サービスを作ることはできます。

Service が停止される場合とその対処法

アプリがアップデートされて Service が停止する場合
以下の記事の BroadcastReceiver で startService する。
[Android]アプリがアップデートしたことを検知するBroadcastReceiver | DevAchieve

端末が再起動されて Service が停止している場合
以下の記事の BroadcastReceiver で startService する。
[Android]端末の起動完了を検知するBroadcastReceiver | DevAchieve

OSがメモリなどのリソースが少なくなり Service が強制的に停止された場合
public class RevivalService extends Service {
    @Override
    public int onStartCommand(Intent intent, int flags, int startId){
        return Service.START_STICKY;
    }
}
Service#onStartCommand で返すフラグによる動作の違いについては以下の記事が詳しいです。
Yukiの枝折: Android:Serviceの基本とonStartCommandの戻り値による動作の違い
onStartCommand で START_STICKY を使うと
強制終了からの再起動時に intent に null になっているという問題があります。
実験的に作ったサンプルプログラムでは、「戻る」コマンドを実行した程度では、このような現象は発生しない。
この問題をサンプルプログラムで再現するには、DDMSのStop Processを使って、プロセスを強制終了させれば良い。そうすれば、しばらく経つと、Serviceが起動してくる。
onStartメソッド又はonStartCommandメソッドを実行してしまったServiceで、この問題は発生する。
bindServiceメソッドだけを使って生成したServiceでは、(onStartメソッド又はonStartCommandメソッドは実行されないので)このような問題は発生しない。
Androyer in Japan: onStartCommandとその戻値について

参考: kino's blog: Android Service を自動的に再起動する方法

ユーザー操作により[設定 > アプリ > 実行中]から Service が停止された場合
以下のコードのように Service#onDestroy で startService すれば再起動可能です。
public class RevivalService extends Service {    
    @Override
    public void onDestroy(){
        super.onDestroy();
        startService(new Intent(this, RevivalService.class));
    }
}
ですが、ユーザーの確固たる意志で Service を停止しているものを無視して再起動するのですから
アンインストールされたり☆1のレビューが増えたりすることは覚悟した上で実装することになります。
本当にそこまで実装する必要があるか要件と向き合う必要があると思います。

おまけ

別プロセスの2つの Service で相互に bindService すれば落ちないようです。
ITで何かできないかを考えてみる Androidで死なないServiceを実装してみた
こちらはこちらで少し気持ち悪い気がしますね。