Service
は、長時間実行オペレーションをバックグラウンドで実行できるアプリケーション コンポーネントです。ユーザー インターフェースは提供されません。サービスは、ユーザーが別のアプリに切り替えた後も、しばらく実行され続けることがあります。また、コンポーネントはサービスにバインドしてサービスとやり取りしたり、プロセス間通信(IPC)を実行したりすることもできます。たとえば、サービスはネットワーク トランザクションの処理、音楽の再生、ファイル I/O の実行、コンテンツ プロバイダとのやり取りをすべてバックグラウンドで行うことができます。
注意: サービスはホスト プロセスのメインスレッドで実行されます。サービスは独自のスレッドを作成しません。また、特に指定しない限り、別のプロセスで実行されません。アプリケーション応答なし(ANR)エラーを回避するには、ブロック処理をサービスの別のスレッドで実行する必要があります。
Service のタイプ
サービスには次の 3 種類があります。
- フォアグラウンド
-
フォアグラウンド サービスは、ユーザーが認識できるオペレーションを実行します。たとえば、オーディオ アプリはフォアグラウンド サービスを使用してオーディオ トラックを再生します。フォアグラウンド サービスは通知を表示する必要があります。フォアグラウンド サービスは、ユーザーがアプリを操作していない場合でも実行を継続します。
フォアグラウンド サービスを使用する場合は、サービスが実行されていることをユーザーが積極的に認識できるように、通知を表示する必要があります。この通知は、サービスを停止するか、フォアグラウンドから削除しない限り、閉じることはできません。
詳しくは、アプリでフォアグラウンド サービスを構成する方法をご覧ください。
注: WorkManager API を使用すると、タスクのスケジュールを柔軟に設定できます。また、必要に応じてこれらのジョブをフォアグラウンド サービスとして実行することもできます。多くの場合、フォアグラウンド サービスを直接使用するよりも、WorkManager を使用することをおすすめします。
- 背景
- バックグラウンド サービスは、ユーザーが直接認識できないオペレーションを実行します。たとえば、アプリがサービスを使用しているストレージを圧縮する場合、通常はバックグラウンド サービスになります。
注: アプリのターゲットが API レベル 26 以降の場合、アプリ自体がフォアグラウンドにない場合、システムはバックグラウンド サービスの実行に制限を課します。たとえば、ほとんどの場合、バックグラウンドから位置情報にアクセスしないでください。代わりに、WorkManager を使用してタスクをスケジュール設定します。
- バインド済み
- サービスがバインドされると、アプリ コンポーネントが
bindService()
を呼び出してサービスにバインドします。バインドされたサービスは、コンポーネントがサービスとやり取りし、リクエストを送信し、結果を受信できるようにするクライアント サーバー インターフェースを提供します。また、プロセス間通信(IPC)を使用してプロセス間でやり取りすることもできます。バインドされたサービスは、別のアプリ コンポーネントがバインドされている間だけ実行されます。複数のコンポーネントを一度にサービスにバインドできますが、それらのコンポーネントがすべてバインド解除されると、サービスは破棄されます。
このドキュメントでは、一般に開始されたサービスとバインドされたサービスを別々に説明していますが、サービスは両方の方法で動作できます。つまり、開始して(無期限に)実行することも、バインドすることもできます。コンポーネントが開始できるようにする onStartCommand()
と、バインディングを許可する onBind()
の 2 つのコールバック メソッドを実装するかどうかの問題です。
サービスが開始されているか、バインドされているか、またはその両方であるかにかかわらず、どのアプリ コンポーネントも、どのコンポーネントでもアクティビティを使用できる方法と同じように(Intent
で開始する)、サービスを使用できます(別のアプリからでも)。ただし、マニフェスト ファイルでサービスを非公開として宣言し、他のアプリからのアクセスをブロックすることはできます。これについては、マニフェストでサービスを宣言するをご覧ください。
サービスとスレッドの選択
サービスは、ユーザーがアプリを操作していない場合でもバックグラウンドで実行できるコンポーネントにすぎません。そのため、サービスは必要に応じてのみ作成する必要があります。
メインスレッドの外部で処理を実行する必要があるが、ユーザーがアプリを操作している間のみ実行する必要がある場合は、別のアプリ コンポーネントのコンテキストで新しいスレッドを作成する必要があります。たとえば、アクティビティの実行中のみ音楽を再生する場合は、onCreate()
でスレッドを作成し、onStart()
で実行を開始し、onStop()
で停止します。また、従来の Thread
クラスではなく、java.util.concurrent
パッケージのスレッドプールとエグゼキュータ、または Kotlin コルーチンの使用も検討してください。実行をバックグラウンド スレッドに移動する方法については、Android でのスレッド化のドキュメントをご覧ください。
サービスを使用する場合でも、デフォルトではアプリのメインスレッドで実行されるため、サービスで負荷の高いオペレーションやブロック オペレーションを実行する場合は、サービス内に新しいスレッドを作成する必要があります。
基本情報
サービスを作成するには、Service
のサブクラスを作成するか、既存のサブクラスを使用する必要があります。実装では、サービス ライフサイクルの重要な部分を処理する一部のコールバック メソッドをオーバーライドし、必要に応じて、コンポーネントがサービスにバインドできるようにするメカニズムを提供する必要があります。以下は、オーバーライドする必要がある最も重要なコールバック メソッドです。
onStartCommand()
- 別のコンポーネント(アクティビティなど)がサービスの開始をリクエストすると、システムは
startService()
を呼び出してこのメソッドを呼び出します。このメソッドが実行されると、サービスが開始され、バックグラウンドで無期限に実行できます。これを実装する場合は、処理が完了したらstopSelf()
またはstopService()
を呼び出してサービスを停止する責任があります。バインドのみを提供する場合は、このメソッドを実装する必要はありません。 onBind()
- 別のコンポーネントがサービスにバインドしようとすると(RPC を実行する場合など)、システムは
bindService()
を呼び出してこのメソッドを呼び出します。このメソッドの実装では、クライアントがIBinder
を返すことでサービスと通信するために使用するインターフェースを提供する必要があります。このメソッドは常に実装する必要があります。ただし、バインディングを許可しない場合は、null を返す必要があります。 onCreate()
- システムは、サービスが最初に作成されたときに(
onStartCommand()
またはonBind()
を呼び出す前に)、このメソッドを呼び出して 1 回限りのセットアップ プロシージャを実行します。サービスがすでに実行されている場合、このメソッドは呼び出されません。 onDestroy()
- サービスが使用されなくなり破棄されると、システムはこのメソッドを呼び出します。サービスは、スレッド、登録済みリスナー、レシーバなどのリソースをクリーンアップするために、このメソッドを実装する必要があります。これは、サービスが受信する最後の呼び出しです。
コンポーネントが startService()
を呼び出してサービスを開始した場合(onStartCommand()
が呼び出される結果)、サービスは stopSelf()
で自ら停止するか、別のコンポーネントが stopService()
を呼び出して停止するまで実行を続けます。
コンポーネントが bindService()
を呼び出してサービスを作成し、onStartCommand()
が呼び出されない場合は、コンポーネントがサービスにバインドされている間のみ、サービスが実行されます。サービスがすべてのクライアントからアンバインドされると、システムはサービスを破棄します。
Android システムは、メモリが不足し、ユーザーがフォーカスしているアクティビティのシステム リソースを復元する必要がある場合にのみ、サービスを停止します。サービスがユーザーのフォーカスがあるアクティビティにバインドされている場合、強制終了される可能性は低くなります。サービスがフォアグラウンドで実行するように宣言されている場合、強制終了される可能性はほとんどありません。サービスが開始されて長時間実行されている場合、バックグラウンド タスクのリスト内の位置は時間の経過とともに下がり、サービスは強制終了されやすくなります。サービスを開始する場合は、システムによる再起動を適切に処理するように設計する必要があります。システムがサービスを強制終了した場合、リソースが使用可能になり次第再起動されますが、これは onStartCommand()
から返される値にも依存します。システムがサービスを破棄するタイミングについて詳しくは、プロセスとスレッド処理のドキュメントをご覧ください。
以降のセクションでは、startService()
サービス メソッドと bindService()
サービス メソッドを作成する方法と、他のアプリ コンポーネントからそれらを使用する方法について説明します。
マニフェストでサービスを宣言する
アクティビティや他のコンポーネントと同様に、すべてのサービスをアプリのマニフェスト ファイルで宣言する必要があります。
サービスを宣言するには、<application>
要素の子として <service>
要素を追加します。次に例を示します。
<manifest ... > ... <application ... > <service android:name=".ExampleService" /> ... </application> </manifest>
マニフェストでサービスを宣言する方法については、<service>
要素リファレンスをご覧ください。
<service>
要素に含めてプロパティを定義できる他の属性もあります。たとえば、サービスの開始に必要な権限や、サービスの実行プロセスなどです。必須の属性は android:name
属性のみです。この属性は、サービスのクラス名を指定します。アプリを公開した後は、この名前を変更しないでください。サービス開始やバインディングに明示的なインテントに依存しているためにコードが破損するリスクを回避するためです(ブログ投稿「変更できないもの」をご覧ください)。
注意: アプリの安全性を確保するため、Service
の起動には必ず明示的インテントを使用します。このサービスにはインテント フィルタを宣言しないでください。暗黙的インテントを使用してサービスを開始すると、どのサービスがインテントに応答するのかを把握できず、ユーザーにはどのサービスが開始するのかがわからないため、セキュリティ上の危険が伴います。Android 5.0(API レベル 21)以降では、暗黙的インテントを使用して bindService()
を呼び出すと、システムから例外がスローされます。
サービスが自分のアプリでのみ使用できるようにするには、android:exported
属性を含めて false
に設定します。これにより、明示的インテントを使用している場合でも、他のアプリがサービスを起動できなくなります。
注:
デバイスで実行されているサービスを確認できます。認識できないサービスや信頼できないサービスが表示された場合は、サービスを停止できます。ユーザーが誤ってサービスを停止しないようにするには、アプリ マニフェストの <service>
要素に android:description
属性を追加する必要があります。説明には、サービスの機能とメリットを説明する短い文を入力します。
開始されたサービスを作成する
開始されたサービスは、別のコンポーネントが startService()
を呼び出して開始するサービスです。これにより、サービスの onStartCommand()
メソッドが呼び出されます。
サービスを起動すると、サービスを起動したコンポーネントとは独立したライフサイクルが開始されます。サービスを開始したコンポーネントが破棄されても、サービスはバックグラウンドで無期限に実行できます。そのため、サービスはジョブが完了したら stopSelf()
を呼び出して自ら停止する必要があります。または、別のコンポーネントが stopService()
を呼び出して停止することもできます。
アクティビティなどのアプリ コンポーネントは、startService()
を呼び出して、サービスを指定し、サービスが使用するデータを含める Intent
を渡すことで、サービスを起動できます。サービスは、onStartCommand()
メソッドでこの Intent
を受け取ります。
たとえば、アクティビティでオンライン データベースにデータを保存する必要がある場合を考えてみましょう。アクティビティは、コンパニオン サービスを起動して、startService()
にインテントを渡すことで、保存するデータを提供できます。サービスは onStartCommand()
でインテントを受け取り、インターネットに接続してデータベース トランザクションを実行します。トランザクションが完了すると、サービスは停止して破棄されます。
注意: サービスは、デフォルトでは、宣言されているアプリと同じプロセスと、そのアプリのメインスレッドで実行されます。ユーザーが同じアプリのアクティビティを操作しているときに、サービスが負荷の高いオペレーションやブロック オペレーションを実行すると、サービスのアクティビティのパフォーマンスが低下します。アプリケーションのパフォーマンスに影響しないようにするには、サービス内で新しいスレッドを開始します。
Service
クラスは、すべてのサービスの基本クラスです。このクラスを拡張する場合は、サービスがすべての処理を完了できる新しいスレッドを作成することが重要です。サービスはデフォルトでアプリのメインスレッドを使用するため、アプリが実行しているアクティビティのパフォーマンスが低下する可能性があります。
Android フレームワークには、Service
のサブクラスである IntentService
も用意されています。これは、ワーカー スレッドを使用して、すべての開始リクエストを 1 つずつ処理します。バックグラウンド実行制限の導入により、Android 8 Oreo 以降ではうまく機能しないため、新しいアプリではこのクラスの使用はおすすめしません。また、Android 11 以降は非推奨になります。新しいバージョンの Android と互換性のある IntentService
の代わりに、JobIntentService を使用できます。
以降のセクションでは、独自のカスタム サービスを実装する方法について説明しますが、ほとんどのユースケースでは、代わりに WorkManager を使用することを強くおすすめします。Android でのバックグラウンド処理ガイドで、ニーズに合ったソリューションがあるかどうかを確認してください。
Service クラスを拡張する
Service
クラスを拡張して、受信した各インテントを処理できます。基本的な実装は次のようになります。
Kotlin
class HelloService : Service() { private var serviceLooper: Looper? = null private var serviceHandler: ServiceHandler? = null // Handler that receives messages from the thread private inner class ServiceHandler(looper: Looper) : Handler(looper) { override fun handleMessage(msg: Message) { // 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 (e: InterruptedException) { // 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 fun 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("ServiceStartArguments", Process.THREAD_PRIORITY_BACKGROUND).apply { start() // Get the HandlerThread's Looper and use it for our Handler serviceLooper = looper serviceHandler = ServiceHandler(looper) } } override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int { 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 serviceHandler?.obtainMessage()?.also { msg -> msg.arg1 = startId serviceHandler?.sendMessage(msg) } // If we get killed, after returning from here, restart return START_STICKY } override fun onBind(intent: Intent): IBinder? { // We don't provide binding, so return null return null } override fun onDestroy() { Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show() } }
Java
public class HelloService extends Service { private Looper serviceLooper; private ServiceHandler serviceHandler; // 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 doesn't 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 serviceLooper = thread.getLooper(); serviceHandler = new ServiceHandler(serviceLooper); } @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 = serviceHandler.obtainMessage(); msg.arg1 = startId; serviceHandler.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(); } }
サンプルコードでは、onStartCommand()
ですべての着信呼び出しを処理し、バックグラウンド スレッドで実行されている Handler
に処理をポストします。IntentService
と同じように動作し、すべてのリクエストを順番に処理します。複数のリクエストを同時に実行する場合など、スレッドプールで処理を実行するようにコードを変更できます。
onStartCommand()
メソッドは整数を返す必要があります。この整数値は、システムがサービスを強制終了した場合に、システムがサービスをどのように続行するかを記述する値です。onStartCommand()
からの戻り値は、次のいずれかの定数にする必要があります。
START_NOT_STICKY
onStartCommand()
が返された後にシステムがサービスを強制終了した場合、配信する保留中のインテントのみが存在する場合を除き、サービスを再作成しないでください。これは、必要のないときにサービスを実行しないようにし、アプリケーションで未完了のジョブを簡単に再起動できる場合に最も安全なオプションです。START_STICKY
onStartCommand()
が返された後にシステムがサービスを強制終了した場合は、サービスを再作成してonStartCommand()
を呼び出しますが、最後のインテントを再配信しないでください。代わりに、サービスを起動する保留中のインテントがない限り、システムは null インテントを使用してonStartCommand()
を呼び出します。その場合、それらのインテントの配信が行われます。これは、コマンドを実行せず、無期限に実行され、ジョブを待機しているメディア プレーヤー(または同様のサービス)に適しています。START_REDELIVER_INTENT
onStartCommand()
が返された後にシステムがサービスを強制終了した場合は、サービスを再作成し、サービスに配信された最後のインテントを使用してonStartCommand()
を呼び出します。保留中のインテントは順番に配信されます。これは、ファイルのダウンロードなど、すぐに再開する必要があるジョブをアクティブに実行しているサービスに適しています。
これらの戻り値の詳細については、各定数のリンク先のリファレンス ドキュメントをご覧ください。
サービスの開始
アクティビティまたは他のアプリ コンポーネントからサービスを開始するには、Intent
を startService()
または startForegroundService()
に渡します。Android システムは、サービスの onStartCommand()
メソッドを呼び出し、開始するサービスを指定する Intent
を渡します。
注: アプリが API レベル 26 以降をターゲットとしている場合、アプリ自体がフォアグラウンドにある場合を除き、バックグラウンド サービスの使用や作成に制限が適用されます。アプリでフォアグラウンド サービスを作成する必要がある場合は、startForegroundService()
を呼び出す必要があります。このメソッドはバックグラウンド サービスを作成しますが、サービスがフォアグラウンドに昇格することをシステムに通知します。サービスが作成されたら、5 秒以内に startForeground()
メソッドを呼び出す必要があります。
たとえば、アクティビティは、startService()
を含む明示的なインテントを使用して、前のセクションのサンプル サービス(HelloService
)を開始できます。
Kotlin
startService(Intent(this, HelloService::class.java))
Java
startService(new Intent(this, HelloService.class));
startService()
メソッドはすぐに返され、Android システムはサービスの onStartCommand()
メソッドを呼び出します。サービスがまだ実行されていない場合、システムはまず onCreate()
を呼び出し、次に onStartCommand()
を呼び出します。
サービスがバインディングも提供していない場合、startService()
で配信されるインテントは、アプリケーション コンポーネントとサービス間の唯一の通信モードです。ただし、サービスを開始したクライアントが、サービスを開始した Intent
でブロードキャスト用の PendingIntent
を作成してサービスに送信することで、サービスを開始したクライアントが結果をサービスに返すようにすることもできます。getBroadcast()
サービスはブロードキャストを使用して結果を配信できます。
サービスを起動するためのリクエストが複数ある場合、サービス onStartCommand()
が複数回呼び出されます。ただし、サービスを停止するには、サービスを停止するリクエスト(stopSelf()
または stopService()
を使用)を 1 回だけ行う必要があります。
サービスの停止
開始されたサービスは、独自のライフサイクルを管理する必要があります。つまり、システム メモリの回復が必要でない限り、システムはサービスを停止または破棄せず、onStartCommand()
が返された後もサービスは実行を続けます。サービスは stopSelf()
を呼び出して自ら停止する必要があります。または、別のコンポーネントが stopService()
を呼び出して停止することもできます。
stopSelf()
または stopService()
で停止をリクエストすると、システムはできる限り早くサービスを破棄します。
サービスが onStartCommand()
への複数のリクエストを同時に処理する場合、新しい開始リクエストを受信する可能性があるため、開始リクエストの処理が完了したときにサービスを停止しないでください(最初のリクエストの終了時に停止すると、2 番目のリクエストが終了します)。この問題を回避するには、stopSelf(int)
を使用して、サービスの停止リクエストが常に最新の開始リクエストに基づいていることを確認します。つまり、stopSelf(int)
を呼び出すときに、停止リクエストに対応する開始リクエストの ID(onStartCommand()
に配信された startId
)を渡します。その後、stopSelf(int)
を呼び出す前にサービスが新しい開始リクエストを受信すると、ID が一致せず、サービスは停止しません。
注意: システム リソースの浪費やバッテリーの消費を避けるため、アプリが処理を完了したらサービスを停止するようにしてください。必要に応じて、他のコンポーネントは stopService()
を呼び出してサービスを停止できます。サービスのバインディングを有効にしても、onStartCommand()
の呼び出しを受け取った場合は、必ず自分でサービスを停止する必要があります。
サービスのライフサイクルについて詳しくは、サービスのライフサイクルを管理するをご覧ください。
バインドされたサービスを作成する
バインドされたサービスは、アプリ コンポーネントが bindService()
を呼び出して長時間の接続を確立することで、そのサービスにバインドできるようにするサービスです。通常、コンポーネントが startService()
を呼び出してこれを開始することはできません。
アプリケーション内のアクティビティや他のコンポーネントからサービスとやり取りする場合や、プロセス間通信(IPC)を介してアプリケーションの一部機能を他のアプリに公開する場合は、バインドされたサービスを作成します。
バインドされたサービスを作成するには、onBind()
コールバック メソッドを実装して、サービスとの通信用のインターフェースを定義する IBinder
を返します。他のアプリ コンポーネントは bindService()
を呼び出してインターフェースを取得し、サービスでメソッドの呼び出しを開始できます。サービスは、バインドされているアプリ コンポーネントにサービスを提供するためにのみ存在するため、サービスにバインドされているコンポーネントがない場合、システムはサービスを破棄します。onStartCommand()
でサービスを開始する場合と同じように、バインドされたサービスを停止する必要はありません。
バインドされたサービスを作成するには、クライアントがサービスと通信する方法を指定するインターフェースを定義する必要があります。サービスとクライアント間のこのインターフェースは IBinder
の実装である必要があります。これは、サービスが onBind()
コールバック メソッドから返す必要があります。クライアントは IBinder
を受信した後、そのインターフェースを介してサービスとのやり取りを開始できます。
複数のクライアントがサービスに同時にバインドできます。クライアントがサービスとのやり取りを完了すると、unbindService()
を呼び出してアンバインドします。サービスにバインドされているクライアントがなくなると、システムはサービスを破棄します。
バインドされたサービスを実装する方法は複数あり、実装は開始されたサービスよりも複雑です。このような理由から、バインドされたサービスについては、バインドされたサービスに関する別のドキュメントで説明しています。
ユーザーへの通知の送信
サービスが実行されているときに、スナックバー通知またはステータスバー通知を使用してイベントをユーザーに通知できます。
スナックバー通知は、現在のウィンドウのサーフェスに一時的に表示されるメッセージです。ステータスバー通知は、ステータスバーにメッセージ付きのアイコンを表示します。ユーザーは、このアイコンを選択してアクション(アクティビティの開始など)を実行できます。
通常、ファイルのダウンロードなどのバックグラウンド処理が完了し、ユーザーがその処理に対応できるようになった場合は、ステータスバー通知を使用するのが最適な方法です。ユーザーが展開ビューから通知を選択すると、通知によってアクティビティが開始されます(ダウンロードしたファイルを表示するなど)。
サービスのライフサイクルを管理する
サービスのライフサイクルは、アクティビティのライフサイクルよりもはるかにシンプルです。ただし、サービスはユーザーに気付かれることなくバックグラウンドで実行される可能性があるため、サービスの作成と破棄に細心の注意を払うことがさらに重要になります。
サービスのライフサイクル(作成から破棄まで)は、次の 2 つのパスのいずれかになります。
- 開始されたサービス
サービスは、別のコンポーネントが
startService()
を呼び出すときに作成されます。サービスはその後無期限に実行され、stopSelf()
を呼び出して停止する必要があります。別のコンポーネントがstopService()
を呼び出してサービスを停止することもできます。サービスが停止すると、システムによって破棄されます。 - バインドされたサービス
サービスは、別のコンポーネント(クライアント)が
bindService()
を呼び出すときに作成されます。クライアントは、IBinder
インターフェースを介してサービスと通信します。クライアントはunbindService()
を呼び出して接続を閉じることができます。複数のクライアントが同じサービスにバインドできます。すべてのクライアントがアンバインドすると、システムはサービスを破棄します。サービスは自身を停止する必要はありません。
これらの 2 つのパスは完全には分離されていません。startService()
ですでに開始されているサービスにバインドできます。たとえば、再生する音楽を識別する Intent
を指定して startService()
を呼び出すと、バックグラウンド音楽サービスを開始できます。後で、ユーザーがプレーヤーを操作したり、現在の曲に関する情報を取得したりするときに、アクティビティは bindService()
を呼び出してサービスにバインドできます。このような場合、stopService()
または stopSelf()
は、すべてのクライアントがバインド解除されるまで、実際にはサービスを停止しません。
ライフサイクル コールバックの実装
アクティビティと同様に、サービスにはライフサイクル コールバック メソッドがあります。このメソッドを実装すると、サービスの状態の変化をモニタリングし、適切なタイミングで処理を実行できます。次のスケルトン サービスは、各ライフサイクル メソッドを示しています。
Kotlin
class ExampleService : Service() { private var startMode: Int = 0 // indicates how to behave if the service is killed private var binder: IBinder? = null // interface for clients that bind private var allowRebind: Boolean = false // indicates whether onRebind should be used override funonCreate
() { // The service is being created } override funonStartCommand
(intent: Intent?, flags: Int, startId: Int): Int { // The service is starting, due to a call to startService() return startMode } override funonBind
(intent: Intent): IBinder? { // A client is binding to the service with bindService() return binder } override funonUnbind
(intent: Intent): Boolean { // All clients have unbound with unbindService() return allowRebind } override funonRebind
(intent: Intent) { // A client is binding to the service with bindService(), // after onUnbind() has already been called } override funonDestroy
() { // The service is no longer used and is being destroyed } }
Java
public class ExampleService extends Service { int startMode; // indicates how to behave if the service is killed IBinder binder; // interface for clients that bind boolean allowRebind; // indicates whether onRebind should be used @Override public voidonCreate
() { // The service is being created } @Override public intonStartCommand
(Intent intent, int flags, int startId) { // The service is starting, due to a call tostartService()
return startMode; } @Override public IBinderonBind
(Intent intent) { // A client is binding to the service withbindService()
return binder; } @Override public booleanonUnbind
(Intent intent) { // All clients have unbound withunbindService()
return allowRebind; } @Override public voidonRebind
(Intent intent) { // A client is binding to the service withbindService()
, // after onUnbind() has already been called } @Override public voidonDestroy
() { // The service is no longer used and is being destroyed } }
注: アクティビティのライフサイクル コールバック メソッドとは異なり、これらのコールバック メソッドのスーパークラスの実装を呼び出す必要はありません。
図 2 は、サービスの一般的なコールバック メソッドを示しています。この図では、startService()
によって作成されたサービスと bindService()
によって作成されたサービスを区別していますが、どのサービスでも、どのように開始されたかにかかわらず、クライアントがサービスにバインドできる可能性があります。最初に onStartCommand()
で開始されたサービス(startService()
を呼び出すクライアントによって開始されたサービス)は、引き続き onBind()
への呼び出しを受け取ることができます(クライアントが bindService()
を呼び出す場合)。
これらのメソッドを実装すると、サービスのライフサイクルの次の 2 つのネストされたループをモニタリングできます。
- サービスの全ライフサイクルは、
onCreate()
が呼び出されてからonDestroy()
が返されるまでの間です。アクティビティと同様に、サービスはonCreate()
で初期設定を行い、onDestroy()
で残りのリソースをすべて解放します。たとえば、音楽再生サービスは、onCreate()
で音楽を再生するスレッドを作成し、onDestroy()
でスレッドを停止できます。注:
onCreate()
メソッドとonDestroy()
メソッドは、startService()
またはbindService()
によって作成されたかどうかにかかわらず、すべてのサービスに対して呼び出されます。 - サービスのアクティブな存続期間は、
onStartCommand()
またはonBind()
の呼び出しで始まります。各メソッドには、startService()
またはbindService()
に渡されたIntent
が渡されます。サービスが開始された場合、アクティブな存続期間は全体的な存続期間の終了と同時に終了します(
onStartCommand()
が返された後もサービスはアクティブなままです)。サービスがバインドされている場合、アクティブな存続期間はonUnbind()
が返された時点で終了します。
注: 開始されたサービスは stopSelf()
または stopService()
の呼び出しによって停止されますが、サービスに固有のコールバックはありません(onStop()
コールバックはありません)。サービスがクライアントにバインドされていない限り、サービスが停止されるとシステムによって破棄されます。onDestroy()
は受信される唯一のコールバックです。
バインディングを提供するサービスの作成の詳細については、バインドされたサービスのドキュメントをご覧ください。このドキュメントの バインドされたサービスのライフサイクルを管理するセクションに、onRebind()
コールバック メソッドの詳細が記載されています。