この記事では、Androidアプリ開発における重要なコンポーネントの1つであるAndroid Serviceについて説明します。Activityとは異なり、ServiceはAndroidでバックグラウンドで動作し、ServiceにはUIがなく、ライフサイクルもActivityとは異なります。Serviceを使用すると、リモートサーバーからWebページを読み込むなどのバックグラウンド操作を実装できます。また、Serviceを使用してAndroidでマルチタスクを実装することもできます。

Android Serviceの概要

ご存知のように、システムリソースが逼迫すると、Android Activityは起動、停止、破棄、さらには再作成される可能性があります。一方、Serviceはより長いライフサイクルを持つように設計されています。ServiceはAndroidでは、Activity、ブロードキャストレシーバー(Broadcast receiver)、または他のServiceから起動できます。

注意すべき点は、Serviceを使用しても自動的に新しいスレッドが作成されるわけではないことです。したがって、Service内で単純なロジックを実装し、長時間の処理が必要ない場合は、別のスレッドで実行する必要はありません。しかし、複雑なロジックを実装し、長時間の処理が必要な場合は、新しいスレッドを作成する際に注意しなければなりません。そうしないと、Serviceがメインスレッドで実行されているため、ANR問題(アプリケーションが応答しない)を引き起こす可能性があります。

AndroidにおけるServiceの主な用途は以下のとおりです。

  • マルチタスクの実装(multi-task)
  • プロセス間通信(IPC)

最初のケースの典型的な例は、アプリがリモートサーバーからデータをダウンロードする必要がある場合です。この場合、ユーザーと対話するActivityを使用し、ユーザーがアプリを使用している間にServiceを起動して、バックグラウンドで処理を完了させることができます。もう1つのシナリオは、Serviceがタスクを完了したときにユーザーに情報を送信する場合です。

2番目のケースでは、いくつかの一般的な機能を「共有」して、異なるアプリがそれらを再利用できるようにしたい場合です。例えば、メールを送信できるServiceがあると仮定します。このServiceを複数のアプリで共有したい場合、同じコードを書き直す必要がありません。この場合、IPCを使用してServiceに「リモート」インターフェースを公開し、他のアプリが呼び出せるようにします。

Serviceの基本

ここまででServiceについてより詳しく理解できたので、作成してみましょう。AndroidでServiceを作成するには、Serviceクラスを継承する必要があります。

public class TestService extends Service {

    @Override
    public IBinder onBind(Intent arg0) {        
        return null;
    }

}

ご覧のとおり、onBindeというメソッドだけを実装しています。上記の例ではローカルサービスを使用しているため、メソッドはnullを返します。前述のように、Serviceには独自のライフサイクルがあるため、いくつかのコールバックメソッドをオーバーライドして、異なる状態を処理できます:

public class TestService extends Service {

    @Override
    public void onCreate() {        
        super.onCreate();
    }

    @Override
    public void onDestroy() {        
        super.onDestroy();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {        
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public IBinder onBind(Intent arg0) {        
        return null;
    }

}

最初のメソッドonCreateは、Serviceが作成されたときにのみ呼び出されます。Serviceがすでに実行中の場合は、このメソッドは呼び出されません。直接呼び出すことはできず、システムによって呼び出されます。

OnStartCommandメソッドは最も重要なメソッドです。Serviceを起動する必要があるときに呼び出されるからです。このメソッドでは、Serviceの実行時に渡されるIntentを取得できるため、Serviceと情報を交換できます。このメソッドでは、独自のロジックを実装します。時間のかからない操作であれば直接このメソッド内で実行できますが、そうでなければスレッドを作成できます。ご覧のように、このメソッドは整数値を返す必要があります。この整数は、システムがこのServiceをどのように処理すべきかを表します:

  • START_STICKY:この戻り値を使用すると、システムがServiceを強制終了した場合、Serviceは再作成されます。ただし、Serviceに送信されたIntentは再配信されません。これにより、Serviceは常に実行され続けます。
  • START_NOT_STICKY:システムがServiceを強制終了しても、クライアントが明示的にonStartコマンドを呼び出さない限り、再作成されません。
  • START_REDELIVER_INTENT:機能はSTART_STICKYと似ています。さらに、この場合IntentはServiceに再配信されます。

OnDestoryは、Serviceが破棄されるときにシステムによって呼び出されるメソッドです。

カスタムServiceクラスを作成したら、Manifest.xmlで宣言する必要があります。これで使用できるようになります。

<service android:name=".TestService"
         android:enabled="true"/>

Serviceの起動と停止

ご存知のように、Serviceは起動され、最終的には停止されて、そのタスクを完了します。ActivityからServiceを起動すると仮定しましょう。Intentを使用してServiceに情報を渡すことができます。Activityに2つのボタンがあり、1つはServiceを起動し、もう1つは停止すると仮定します:

btnStart.setOnClickListener(new View.OnClickListener() {
 
    @Override
    public void onClick(View v) {
        Intent i = new Intent(MainActivity.this, TestService.class);
        i.putExtra("name", "SurvivingwithAndroid");        
        MainActivity.this.startService(i);        
    }
});
 
btnStop.setOnClickListener(new View.OnClickListener() {
 
    @Override
    public void onClick(View v) {
        Intent i = new Intent(MainActivity.this, TestService.class);
        MainActivity.this.stopService(i);
    }
});

上記のサンプルコードの5行目では、サービスの処理にクラス名を渡すIntentを作成し、名前などのパラメータを設定しています。そして7行目でこのServiceを起動します。同様に、17行目でこのServiceを停止します。

android-service-tutorial-1

開始ボタンをクリックすると、次のLogが得られます:

android-service-tutorial-2

onCreateメソッドが呼び出されていることに気付くでしょう。これはこのServiceを初めて起動したためです。開始ボタンを再度クリックしても、システムはonCreateメソッドを呼び出しません。停止ボタンをクリックすると、システムはこのServiceを破棄します。

IntentService

前述のように、Serviceはメインスレッドで実行されます。そのため、Service内でロジックを実装する際は非常に注意が必要です。このロジックがブロッキング操作であるか、完了するまでに長い時間がかかる場合、ANR問題を引き起こす可能性があります。このような場合は、ロジックを独立したスレッドに移動する必要があります。つまり、onStartCommandメソッド内でスレッドを作成し、それを実行します。

Serviceから派生したもう1つのIntentServiceクラスは、開発を簡素化できます。同時に複数のリクエストを処理する必要がない場合、このクラスは便利です。このクラスは、異なるリクエストを処理するためのワーカースレッドを作成します。実行される操作は次のとおりです:

  • リクエストを処理するための専用のスレッドを作成します。
  • リクエストキューを作成し、Intentを1つずつ渡します。
  • デフォルトのonStartCommand実装を作成します。
  • すべてのリクエストの実行が完了したらServiceを終了します。

IntentServiceを作成したい場合は、ServiceクラスではなくIntentServiceクラスを継承する必要があります:

public class TestIntentService extends IntentService {
 
    public TestIntentService() {
        super("TestIntentService");        
    }
 
    @Override
    protected void onHandleIntent(Intent intent) {
 
    }
 
}

この例では、onHandleIntentメソッドを実装するだけです。ここで実装するロジックは、操作が時間がかかるかどうかを気にする必要はありません。このメソッドは別のスレッドで呼び出されるためです。

Serviceの自動起動

多くの場合、Serviceを自動起動したいことがあります。例えば、起動時に自動起動する場合などです。Serviceを起動するにはコンポーネントが必要であることはわかっています。では、どうやって自動起動を実現するのでしょうか?ブロードキャストレシーバーを使用してServiceを起動できます。例えば、スマートフォンの起動時にServiceを起動したい場合、まずこのイベント(起動)をリッスンするブロードキャストレシーバーを作成し、それからServiceを起動します。

public class BootBroadcast extends BroadcastReceiver {

    @Override
    public void onReceive(Context ctx, Intent intent) {        
        ctx.startService(new Intent(ctx, TestService.class));

    }

}

Manifest.xmlで宣言します:

<receiver android:name=".BootBroadcast">    
    <intent-filter >
        <action android:name="android.intent.action.BOOT_COMPLETED"/>                
    </intent-filter>
</receiver>

出典:http://www.importnew.com/9019.html