サービス

Service は、バックグラウンドで長時間動作して作業を行い、ユーザー インターフェースを表示しないアプリケーション コンポーネントです。 別のアプリケーション コンポーネントがサービスを開始し、ユーザーが他のアプリケーションに切り替えた場合でも、サービスはバックグラウンドで実行し続けることができます。 さらに、コンポーネントをサービスにバインドして操作したり、プロセス間通信(IPC)を実行したりすることも可能です。 たとえば、サービスはネットワーク トランザクションの処理、音楽の再生、ファイルの I/O の実行、コンテンツ プロバイダとのやり取りなどのすべてをバックグラウンドで行うことができます。

サービスには、基本的に次の 2 つの形式があります。

開始されたサービス
アプリケーション コンポーネント(アクティビティなど)が startService() を呼び出して開始したときに、サービスが「開始された」状態になります。 一旦開始されると、たとえ開始したコンポーネントが破棄されても、サービスは無期限に実行できます。 通常、開始されたサービスは 1 つの操作を実行するだけで、呼び出し元に結果を返すことはありません。たとえば、サービスはネットワーク上でファイルのダウンロードやアップロードを行います。 操作が完了すると、サービスは自身で停止する必要があります。
バインドされたサービス
アプリケーション コンポーネントが bindService() を呼び出してサービスにバインドすると、サービスは「バインドされた」状態になります。バインドされたサービスは、コンポーネントがサービスを操作したり、要求を送信したり、結果を取得したり、さらにはプロセス間通信(IPC)でもそれを行えるクライアントサーバー型インターフェースを提供します。 バインドされたサービスは、他のアプリケーション コンポーネントがそれにバインドしている限り実行し続けます。 サービスには同時に複数のコンポーネントがバインドできますが、すべてがアンバインドされると、サービスは破棄されます。

このドキュメントではこの 2 種類のサービスそれぞれの概要について説明しますが、サービスは開始された状態(無期限に実行)、バインドされた状態のどちらの方法でも動作できます。これは、2 つのコールバック メソッドを実装するかどうかの問題で、onStartCommand() ではコンポーネントにサービスの開始を許可し、onBind() ではバインドを許可することになります。

アプリケーションが開始された、バインドされた、またはその両方かであるかどうかにかかわらず、どんなコンポーネントでもアクティビティを使用できるのと同じように、Intent を使って開始することで、どんなアプリケーション コンポーネントでもサービスを使用できます。 ただし、マニフェスト ファイルでサービスを非公開として宣言して、他のアプリケーションからのアクセスをブロックすることもできます。 詳細については、マニフェストでサービスを宣言するで説明します。

警告: サービスは、そのホスト プロセスのメインスレッドで実行します。サービスが自身のスレッドを作成することはなく、別のプロセスで実行されることもありません(別の方法を指定しない限り)。 つまり、サービスが CPU を集中的に使ったり、ブロック操作を行ったりするような場合(MP3 の再生やネットワーク作業)は、サービス内に新しいスレッドを作成してその作業を行う必要があります。 別のスレッドを使うことで、「アプリケーションが応答していません (ANR)」のエラーが発生するリスクを軽減でき、アプリケーションのメインスレッドをアクティビティのユーザー操作専用にすることができます。

基本

サービスを作成するには、Service のサブクラス(またはその既存のサブクラス)を作成する必要があります。 実装時には、サービスのライフサイクルの重要側面を扱うコールバック メソッドをオーバーライドして、必要に応じてサービスにバインドするためのメカニズムをコンポーネントに提供する必要があります。 オーバーライドする必要のある、最も重要なコールバック メソッドは次の 2 つです。

onStartCommand()
アクティビティなどの他のコンポーネントが、startService() を呼び出してサービスの開始を要求したときに、システムがこのメソッドを呼び出します。 このメソッドが実行されるとサービスは開始され、バックグラウンドで無期限に実行します。 これを実装すると、作業完了時に stopSelf()stopService() を呼び出して自身でサービスを停止する必要があります (バインドのみを提供する場合は、このメソッドを実装する必要はありません)。
onBind()
bindService() を呼び出して他のコンポーネントをサービスにバインドさせるとき(RPC 実行時など)に、システムがこのメソッドを呼び出します。 このメソッドの実装時には、IBinder を返してクライアントがサービスとの通信に使うインターフェースを提供する必要があります。 このメソッドの実装は常に必要ですが、バインドを許可しない場合は、null を返す必要があります。
onCreate()
サービスが始めて作成されたときに、1 回限りのセットアップ処理を実行するためにシステムがこのメソッドを呼び出します(onStartCommand()onBind() のいずれかを呼び出す前)。 サービスが既に実行中の場合、このメソッドは呼び出されません。
onDestroy()
サービスがもう使用されておらず破棄されたときに、システムがこのメソッドを呼び出します。これは、スレッドや登録されたリスナ、レシーバーなどをクリーンアップするためにサービスに実装する必要があります。 これが、サービスが受け取る最後の呼び出しになります。

コンポーネントが startService() を呼び出してサービスを開始すると(結果的に onStartCommand() が呼び出される)、stopSelf() を使ってサービス自身が停止するか、他のコンポーネントが stopService() を呼び出して停止するまで、サービスは実行し続けます。

コンポーネントが bindService() を呼び出してサービスを作成した(そして onStartCommand() が呼び出されていない)場合、サービスはコンポーネントにバインドされている間のみ実行します。 すべてのクライアントからアンバインドされると、サービスはシステムによって破棄されます。

Android システムは メモリが少なくなって、ユーザーが使用しているアクティビティ用のシステムリソースを回復させる必要が生じた場合のみ、サービスを強制的に停止させます。 サービスがユーザーが使用しているアクティビティにバインドされている場合は、 それが強制終了される可能性は低く、フォアグラウンドで実行(後で説明)するように宣言されている場合は、強制終了されることはほとんどありません。 一方で、サービスが開始されてから長時間実行している場合は、システムはバックグラウンド タスクのリストにおけるその位置付けを徐々に低くし、そのサービスが強制終了される確率が高くなります。 開始されたサービスを作成する際は、システムによる再起動を円滑に処理するようデザインする必要があります。 システムがサービスを強制終了すると、リソースが回復次第そのサービスが再起動します(後述の onStartCommand() から返される値にもよります)。 システムがサービスを破棄するタイミングについては、プロセスとスレッドのドキュメントをご覧ください。

次のセクションでは、それぞれのタイプのサービスの作成方法と、他のアプリケーション コンポーネントからの使用方法について説明します。

マニフェストでサービスを宣言する

アクティビティ(や他のコンポーネント)と同様に、すべてのサービスをアプリケーションのマニフェスト ファイルで宣言する必要があります。

サービスを宣言するには、<service> 要素を <application> の子要素として追加します。 次に例を示します。

<manifest ... >
  ...
  <application ... >
      <service android:name=".ExampleService" />
      ...
  </application>
</manifest>

マニフェストでのサービスの宣言に関する詳細については、<service> 要素のリファレンスをご覧ください。

<service> に含めることで、サービスやサービスを実行するプロセスの開始に必要なパーミッションなどのプロパティを定義できる他の属性がいくつかあります。 android:name 属性は唯一の必須属性で、サービスのクラス名を指定します。 アプリケーションを発行したら、この名前は変更できません。変更すると、サービスを開始したりバインドしたりする明示的インテントの依存関係によってコードを破損する可能性があります(ブログの投稿 Things That Cannot Change をご覧ください)。

アプリの安全性を保つため、Serviceを開始したりバインドしたりするときは、常に明示的インテントを使用し、サービスでインテント フィルタを宣言しないようにしてください。 どのサービスを開始するかについて、ある程度のあいまいさを残しておく必要がある場合は、サービスにインテント フィルタを定義して、Intent からコンポーネント名を除外して、その後ターゲットのサービスのあいまい性を十分に解消する setPackage() でインテントのパッケージを設定する必要があります。

さらに、android:exported 属性を含めて "false" に設定すると、サービスを自身のアプリでしか利用できないようにできます。 これにより、他のアプリによるサービスの開始を効果的に回避でき、たとえ明示的インテントを使用したとしても開始できなくなります。

開始されたサービスを作成する

開始されたサービスは、他のコンポーネントが startService() を呼び出すことで結果的にサービスの onStartCommand() メソッドを呼び出して開始されたサービスです。

サービスが開始されると、サービスはそれを開始したコンポーネントから独立したライフサイクルを持ち、たとえ開始したコンポーネントが破棄されても、サービスは無期限に実行できます。 そのため、サービスはジョブが完了したら stopSelf() を呼び出して自身で停止する必要があり、他のコンポーネントが stopService() を呼び出して停止することもできます。

アクティビティなどのアプリケーション コンポーネントは、startService() を呼び出して、サービスを指定し、サービスが使用するデータを含めた Intent を渡してサービスを開始できます。 サービスはこの Intent を、onStartCommand() メソッドで受け取ります。

たとえば、オンライン データベースにデータを保存する必要のあるアクティビティがあるとします。アクティビティでサービスを開始し、startService() にインテントを渡して、保存するデータをサービスに配信します。 サービスはインテントを onStartCommand() で受け取り、インターネットに接続してデータベースのトランザクションを実行します。 トランザクションが完了したら、サービスは自身で停止し、破棄されます。

警告: デフォルトでは、アプリケーションで宣言されたサービスは、アプリケーションと同じプロセスで、そのアプリケーションのメインスレッドで実行します。 そのため、ユーザーが同じアプリケーションのアクティビティを操作している間に、サービスが集中的な処理やブロック操作を実行すると、アクティビティのパフォーマンスが低下します。 アプリケーションのパフォーマンスへの影響を回避するには、サービス内で新しいスレッドを開始する必要があります。

従来どおり、開始されたサービスを作成するために拡張できるクラスが 2 つあります。

Service
これは、すべてのサービスの基本クラスです。サービスはデフォルトでアプリケーションのメインスレッドを使用し、アプリケーションが実行しているアクティビティのパフォーマンスを低下させることがあるため、このクラスを拡張するときは、サービスのすべての作業を行うための新しいスレッドを作成することが重要です。
IntentService
すべての開始要求を一件ずつ処理するワーカー スレッドを使用した Service のサブクラスです。 サービスで同時に複数の要求を処理する必要がない場合は、これが最適です。 onHandleIntent() を実装するだけで、それぞれの開始要求のインテントを受け取り、バックグラウンドでの処理が可能になります。

次のセクションでは、これらいずれかのクラスを使用してサービスを実装する方法について説明します。

IntentService クラスを拡張する

開始されたサービスで同時に複数の要求を処理する必要があることはほとんどないため(実際には危険なマルチスレッド シナリオになります)、IntentService クラスを使用してサービスを実装するのが最適だと考えられます。

IntentService は、次の操作を行います。

  • アプリケーションのメインスレッドとは別の onStartCommand() に配信されるすべてのインテントを実行する、デフォルトのワーカー スレッドを作成します。
  • マルチスレッドの懸念を排除するため、一度に 1 つのインテントを onHandleIntent() の実装に渡すワークキューを作成します。
  • stopSelf() を呼び出す必要がないよう、すべての開始要求の処理後にサービスを停止します。
  • Null を返す onBind() のデフォルト実装を提供します。
  • インテントをワークキュー、onHandleIntent() の実装の順に送信する onStartCommand() のデフォルト実装を提供します。

上記すべての操作が行われることで、デベロッパーが行う必要があるのは、クライアントから指示された内容を処理する onHandleIntent() の実装だけになります (ただし、サービスの小さいコンストラクタを提供する必要はあります)。

IntentService の実装例を次に示します。

public class HelloIntentService extends IntentService {

  /**
   * A constructor is required, and must call the super IntentService(String)
   * constructor with a name for the worker thread.
   */
  public HelloIntentService() {
      super("HelloIntentService");
  }

  /**
   * The IntentService calls this method from the default worker thread with
   * the intent that started the service. When this method returns, IntentService
   * stops the service, as appropriate.
   */
  @Override
  protected void onHandleIntent(Intent intent) {
      // Normally we would do some work here, like download a file.
      // For our sample, we just sleep for 5 seconds.
      try {
          Thread.sleep(5000);
      } catch (InterruptedException e) {
          // Restore interrupt status.
          Thread.currentThread().interrupt();
      }
  }
}

コンストラクタと onHandleIntent() の実装、必要なのはこれだけです。

onCreate()onStartCommand()onDestroy() などの他のコールバック メソッドもオーバーライドする場合は、IntentService がワーカー スレッドの生存状態を正しく処理できるよう、必ず super を実装するようにします。

たとえば、onStartCommand() はデフォルト実装を返す必要があります(これによりインテントが onHandleIntent() に配信されます)。

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
    return super.onStartCommand(intent,flags,startId);
}

onHandleIntent() 以外で、super クラスを呼び出す必要のないメソッドは、onBind() です(ただし、サービスでバインドを許可している場合のみ実装が必要です)。

次のセクションでは、この種のサービスが、基本の Service クラスを拡張したときにどのように実装されるかを説明します。 これにはさらに多くのコードがありますが、開始要求の同時処理が必要な場合には適しています。

Service クラスを拡張する

前のセクションで説明したように、IntentService を使用すると開始されたサービスの実装が非常に簡単になります。 ただし、サービスでマルチスレッドを実行する必要がある場合(開始要求をワークキュー経由で処理するのではなく)、Service クラスを拡張して、それぞれのインテントを処理できます。

比較のために次のコードをご覧ください。こちらは IntentService を使用した上記の例とまったく同じ処理を実行する Service クラスの実装例です。つまり、それぞれの開始要求に対し、ワーカー スレッドを使用してジョブとプロセスを実行し、一度に 1 つの要求のみを処理します。

public class HelloService extends Service {
  private Looper mServiceLooper;
  private ServiceHandler mServiceHandler;

  // Handler that receives messages from the thread
  private final class ServiceHandler extends Handler {
      public ServiceHandler(Looper looper) {
          super(looper);
      }
      @Override
      public void handleMessage(Message msg) {
          // Normally we would do some work here, like download a file.
          // For our sample, we just sleep for 5 seconds.
          try {
              Thread.sleep(5000);
          } catch (InterruptedException e) {
              // Restore interrupt status.
              Thread.currentThread().interrupt();
          }
          // Stop the service using the startId, so that we don't stop
          // the service in the middle of handling another job
          stopSelf(msg.arg1);
      }
  }

  @Override
  public void onCreate() {
    // Start up the thread running the service.  Note that we create a
    // separate thread because the service normally runs in the process's
    // main thread, which we don't want to block.  We also make it
    // background priority so CPU-intensive work will not disrupt our UI.
    HandlerThread thread = new HandlerThread("ServiceStartArguments",
            Process.THREAD_PRIORITY_BACKGROUND);
    thread.start();

    // Get the HandlerThread's Looper and use it for our Handler
    mServiceLooper = thread.getLooper();
    mServiceHandler = new ServiceHandler(mServiceLooper);
  }

  @Override
  public int onStartCommand(Intent intent, int flags, int startId) {
      Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();

      // For each start request, send a message to start a job and deliver the
      // start ID so we know which request we're stopping when we finish the job
      Message msg = mServiceHandler.obtainMessage();
      msg.arg1 = startId;
      mServiceHandler.sendMessage(msg);

      // If we get killed, after returning from here, restart
      return START_STICKY;
  }

  @Override
  public IBinder onBind(Intent intent) {
      // We don't provide binding, so return null
      return null;
  }

  @Override
  public void onDestroy() {
    Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
  }
}

このように、IntentService を使う場合よりもかなり面倒です。

ただし、onStartCommand() への各呼び出しを自身で処理するため、同時に複数の要求を実行することも可能です。この例にはあてはまりませんが、自身の状況に合う場合は、要求ごとに新しいスレッドを作成し、すぐに実行することもできます(前の要求が完了するのを待つ必要がありません)。

onStartCommand() メソッドは整数を返す必要があることに注意してください。 この整数は、システムがサービスを強制終了した場合に、サービスをどのように続行させるかを示す値です(前述のように、IntentService のデフォルト実装が代わりにこれを処理しますが、自身で修正することもできます)。 onStartCommand() から返される値は、次のいずれかの定数である必要があります。

START_NOT_STICKY
onStartCommand() から戻った後でシステムがサービスを強制終了した場合は、配信が保留中のインテントがない限りシステムはサービスを再作成しません。 これは、サービスが不必要で、アプリケーションが未完了のジョブを再開できる場合にサービスを実行してしまうのを回避できる最も安全な選択肢です。
START_STICKY
onStartCommand() から戻った後でシステムがサービスを強制終了した場合は、サービスを再作成し、onStartCommand() を呼び出しますが、最後のインテントは再配信しません。サービスを開始するインテントが保留になっている場合を除いて、システムは代わりに onStartCommand() を null インテントを使って呼び出します。保留中のインテントがある場合、そのインテントは配信されます。 これは、コマンドは実行しないが、無期限に実行し、ジョブを待機するメディア プレーヤー(や同様のサービス)に適しています。
START_REDELIVER_INTENT
onStartCommand() から戻った後でシステムがサービスを強制終了した場合は、サービスを再作成し、サービスに最後に配信されたインテントで onStartCommand() を呼び出します。 すべてのペンディング インテントが順に配信されます。これは、ファイルのダウンロードのような、活発にジョブを実行し、ただちに再開する必要のあるサービスに適しています。

これらの戻り値の詳細については、リンクされた各定数のリファレンス ドキュメントをご覧ください。

サービスを開始する

アクティビティや他のアプリケーション コンポーネントから Intent(開始するサービスを指定する)を startService() に渡すことで、サービスを開始できます。 Android システムが、サービスの onStartCommand() メソッドを呼び出して、Intent を渡します(絶対に、onStartCommand() を直接呼び出さないでください)。

アクティビティが前のセクションで例に挙げたサービス(HelloService)を、startService() で明示的インテントを使って開始する例を次に示します。

Intent intent = new Intent(this, HelloService.class);
startService(intent);

startService() メソッドがすぐに戻り、Android システムがサービスの onStartCommand() メソッドを呼び出します。 サービスがまだ実行されていない場合、システムはまず onCreate() を呼び出してから、onStartCommand() を呼び出します。

サービスでバインドが提供されない場合は、startService() で配信されたインテントが、アプリケーション コンポーネントとサービス間の唯一の通信モードになります。 ただし、サービスから結果を送り返す場合は、サービスを開始するクライアントがブロードキャスト用に PendingIntent を作成でき(getBroadcast() で)、それをサービスを開始する Intent のサービスに配信できます。 その後、サービスはブロードキャストを使って結果を配信できます。

サービスを開始する要求が複数ある場合は、それに対応する複数の呼び出しがサービスの onStartCommand() に対して発生することになります。 ただし、サービスを停止するために必要な要求(stopSelf()stopService() を使用)は、1 つのみです。

サービスを停止する

開始されたサービスは、自身でライフサイクルを管理する必要があります。つまり、システムメモリを復元する必要がある場合を除き、システムがサービスを停止したり破棄したりすることはなく、サービスは onStartCommand() から戻った後も実行し続けます。 そのため、サービスは stopSelf() を呼び出して自身で停止する必要があり、他のコンポーネントが stopService() を呼び出して停止することもできます。

stopSelf()stopService() で停止が要求されたら、システムは可能な限りすぐにサービスを破棄します。

ただし、サービスが onStartCommand() への複数の要求を同時に処理している場合は、その後に新しい開始要求を受け取る可能性があることから、開始要求の処理後もサービスを停止しないでください(1 つ目の要求の最後に停止すると、2 つ目が停止されてしまいます)。 この問題を回避するには、stopSelf(int) を使って、常に最新の開始要求に基づいてサービスの停止要求を行うようにできます。 具体的には、stopSelf(int) を呼び出すとき、停止要求に対応する開始要求の ID(onStartCommand() に配信された startId)を渡します。 その後、stopSelf(int) を呼び出す前にサービスが新しい開始要求を受け取ったとしても、結果的に ID が一致せずサービスが停止されなくなります。

警告: アプリケーションはサービスの処理が完了したら、システムリソースやバッテリ電力の節約のため、サービスを停止することが重要です。 必要であれば、他のコンポーネントから stopService() を呼び出してサービスを停止することもできます。 サービスのバインドを有効にしている場合でも、onStartCommand() への呼び出しを受け取ったときには常に自身でサービスを停止する必要があります。

サービスのライフサイクルの詳細については、後半のセクションのサービスのライフサイクルを管理するをご覧ください。

バインドされたサービスを作成する

バインドされたサービスとは、アプリケーション コンポーネントが長時間の接続を作成するために bindService() を呼び出してサービスにバインドできるようにするサービスです(通常はコンポーネントが startService() を呼び出すことではサービスは開始できません)。

バインドされたサービスは、アプリケーションのアクティビティや他のコンポーネントからのサービスとやり取りしたり、アプリケーションの一部の機能をプロセス間通信(IPC)を用いて他のアプリケーションが利用できるようにしたりする場合に作成します。

バインドされたサービスを作成するには、onBind() コールバック メソッドを実装して、サービスとの通信用のインターフェースを定義する IBinder を返す必要があります。 その後、他のアプリケーション コンポーネントが bindService() を呼び出してインターフェースを取得し、サービスのメソッドの呼び出しを開始できます。 サービスは、バインドされているアプリケーション コンポーネントのためだけに存在するため、バインドされているコンポーネントがなくなると、サービスにシステムによって破棄されます(バインドされたサービスは、onStartCommand() でサービスが開始されたときと同じ方法で停止する必要はありません)。

バインドされたサービスを作成するには、まずクライアントからサービスへの通信方法を指定するインターフェースを定義します。 サービスとクライアント間のこのインターフェースは IBinder の実装である必要があり、サービスはこれを onBind() コールバック メソッドから返す必要があります。 クライアントが IBinder を受け取ると、そのインターフェースを介してサービスとのやり取りを開始できます。

複数のクライアントが同時にサービスにバインドできます。クライアントとサービスのやり取りが終わったら、unbindService() を呼び出してアンバインドします。 サービスにバインドされているクライアントがなくなったら、システムがサービスを破棄します。

バインドされたサービスの実装方法はいくつかあり、その実装は開始されたサービスよりも複雑であるため、バインドされたサービスの詳細については、バインドされたサービス のドキュメントで別途説明しています。

ユーザーに通知を送信する

一旦サービスが実行されると、トースト通知ステータスバー通知を使ってユーザーにイベントを通知できます。

トースト通知は、現在のウィンドウに表示されるメッセージで、少しの間表示され、すぐに消えます。一方、ステータスバー通知では、ステータスバーにメッセージの付いたアイコンが表示され、ユーザーはそれを選択して何らかの操作(アクティビティの開始など)を行うことができます。

通常は、バックグラウンド ワークが完了して、ユーザーが実行できる操作がある場合(ファイルのダウンロードが完了した場合など)は、ステータスバーの通知が最適なテクニックです。 展開したビューでユーザーが通知を選択すると、通知がアクティビティ(ダウンロードしたファイルを表示するなど)を開始できるようになります。

詳細については、デベロッパー ガイドのトースト通知ステータスバーの通知をご覧ください。

サービスをフォアグラウンドで実行する

フォアグラウンド サービスは、ユーザーがその存在を認識しているものであるとみなされるため、メモリ残量が少なくなった場合でも、システムによる強制終了の現候補にはなりません。 フォアグラウンド サービスではステータスバーに通知を表示する必要があり、通知は「継続中」という見出しの下に表示されるため、サービスが停止するか、フォアグラウンドから除去しない限り通知を消すことはできないということになります。

たとえば、サービスから音楽を再生する音楽プレーヤーは、ユーザーがその操作を認識しているのは明らかであるため、フォアグラウンドで実行する必要があります。 ステータスバーの通知には現在再生中の曲名を表示でき、ユーザーが音楽プレーヤーを操作するためのアクティビティを起動できるようにできます。

サービスをフォアグラウンドで実行するよう要求するには、startForeground() を呼び出します。このメソッドは、通知を一意に識別する整数と、ステータスバーの Notification の 2 つのパラメータを受け付けます。 次に例を示します。

Notification notification = new Notification(R.drawable.icon, getText(R.string.ticker_text),
        System.currentTimeMillis());
Intent notificationIntent = new Intent(this, ExampleActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
notification.setLatestEventInfo(this, getText(R.string.notification_title),
        getText(R.string.notification_message), pendingIntent);
startForeground(ONGOING_NOTIFICATION_ID, notification);

警告: startForeground() に渡す整数 ID には、0 は使用できません。

サービスをフォアグラウンドから除去するには、stopForeground() を呼び出します。このメソッドでは、同時にステータスバーの通知も除去するかどうかを示すブール値を受け付けます。 このメソッドでは、サービスは停止されません。 ただし、サービスがまだフォアグラウンドで実行中に停止した場合は、通知も除去されます。

通知の詳細については、ステータスバー通知の作成をご覧ください。

サービスのライフサイクルを管理する

サービスのライフサイクルは、アクティビティのライフサイクルよりもはるかにシンプルです。ただし、サービスはバックグラウンドでサイレントに実行されるため、サービスがどのように作成され、破棄されるかについては、より一層の注意を払っておく必要があります。

作成されてから破棄されるまでのサービスのライフサイクルには、2 つの経路があります。

  • 開始されたサービスの場合

    他のコンポーネントが startService() を呼び出したときにサービスが作成されます。その後サービスは無期限に実行し、stopSelf() を呼び出して自身で停止する必要があります。 また、他のコンポーネントから stopService() を呼び出してサービスを停止することもできます。 サービスが停止すると、システムがそれを破棄します。

  • バインドされたサービス

    他のコンポーネント(クライアント)が bindService() を呼び出したときにサービスが作成されます。その後、クライアントが IBinder インターフェースを介してサービスとやり取りします。 クライアントは、unbindService() を呼び出して接続を終了できます。 サービスには同時に複数のクライアントがバインドでき、すべてがアンバインドされると、サービスはシステムによって破棄されます (サービスを自身で停止する必要はありません)。

この 2 つの経路は、完全に分離しているわけではありません。つまり、startService() で既に開始されたサービスにバインドすることも可能です。 たとえば、startService() を呼び出してバックグラウンドの音楽サービスを開始し、Intent を使って再生する音楽を指定できます。 その後、ユーザーがプレーヤーを操作したり、現在の曲に関する情報を入手したりする場合は、bindService() を呼び出すことでアクティビティをサービスにバインドできます。 このような場合は、すべてのクライアントがアンバインドされるまで、stopService()stopSelf() ではサービスは停止されません。

ライフサイクル コールバックを実装する

アクティビティと同様に、サービスにもコールバック メソッドがあり、それを実装することでサービスの状態の変化を監視したり、適切なタイミングで処理を実行したりできます。 次のスケルトン サービスは、それぞれのライフサイクル メソッドを表しています。

public class ExampleService extends Service {
    int mStartMode;       // indicates how to behave if the service is killed
    IBinder mBinder;      // interface for clients that bind
    boolean mAllowRebind; // indicates whether onRebind should be used

    @Override
    public void onCreate() {
        // The service is being created
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // The service is starting, due to a call to startService()
        return mStartMode;
    }
    @Override
    public IBinder onBind(Intent intent) {
        // A client is binding to the service with bindService()
        return mBinder;
    }
    @Override
    public boolean onUnbind(Intent intent) {
        // All clients have unbound with unbindService()
        return mAllowRebind;
    }
    @Override
    public void onRebind(Intent intent) {
        // A client is binding to the service with bindService(),
        // after onUnbind() has already been called
    }
    @Override
    public void onDestroy() {
        // The service is no longer used and is being destroyed
    }
}

注: アクティビティのライフサイクル コールバック メソッドの場合とは異なり、これらのコールバック メソッドのスーパークラスの実装を呼び出す必要はありません。

図 2 サービスのライフサイクル。左側の図は、startService() でサービスが作成されたときのライフサイクルを示し、右側の図は、bindService() でサービスが作成されたときのライフサイクルを示しています。

これらのメソッドを実装すると、サービスのライフサイクル内の次の 2 つのネストされたループを監視できます。

  • サービスの全体の生存期間は、onCreate() が呼び出されてから、onDestroy() から戻るまでの間です。アクティビティと同様に、サービスが onCreate() で初期設定を行い、onDestroy() で残りのすべてのリソースを解放します。 たとえば、音楽再生サービスでは、音楽を再生するスレッドを onCreate() に作成して、onDestroy() でスレッドを停止します。

    onCreate() メソッドと onDestroy() メソッドは、それが startService()bindService() のどちらで作成された場合でも、すべてのサービスに対して呼び出されます。

  • サービスのアクティブな生存期間 は、onStartCommand()onBind() のいずれかへの呼び出しから開始します。各メソッドには、startService()bindService() のいずれかに渡された Intent が渡されます。

    サービスが開始された場合、アクティブな生存期間の完了は、全体の生存期間の完了と同じタイミングとなります(onStartCommand() から戻った後もサービスはまだアクティブです)。 サービスがバインドされた場合、アクティブな生存期間は onUnbind() から戻った時点で終了します。

注: 開始されたサービスは、stopSelf()stopService() への呼び出しで停止されますが、サービスには同様のコールバックはありません(onStop() コールバックがありません)。 そのため、サービスがクライアントにバインドされていない限り、サービスが停止するとシステムがそれを破棄します。受け取るコールバックは onDestroy() のみです。

図 2 は、サービスの典型的なコールバック メソッドを表しています。この図では、startService() で作成されたサービスと bindService() で作成されたサービスを分けていますが、開始方法にかかわらず、すべてのサービスがクライアントからバインドされる可能性があることに注意してください。つまり、当初は onStartCommand() で(クライアントが startService() を呼び出した際)開始されたサービスも、onBind() への呼び出し(クライアントが bindService() を呼び出した際)を受け取ることができます。

バインドを提供するサービスの作成に関する詳細は、バインドされたサービスのドキュメントをご覧ください。このドキュメントのバインドされたサービスのライフサイクルを管理するでは、onRebind() コールバックの詳細についても説明しています。