Service
は、長時間実行オペレーションをバックグラウンドで実行できるアプリ コンポーネントです。ユーザー インターフェースは提供していません。サービスが開始した後は、ユーザーが別のアプリケーションに切り替えた後でも、しばらくの間サービスの実行が継続される場合があります。さらに、コンポーネントは、サービスにバインドして操作したり、プロセス間通信(IPC)を実行したりできます。たとえば、ネットワーク トランザクションの処理、音楽の再生、ファイル I/O の実行、コンテンツ プロバイダとのやり取りをすべてバックグラウンドで行うことができます。
注意: サービスは、ホスティング プロセスのメインスレッドで実行されます。特に指定がない限り、独自のスレッドを作成することはなく、別のプロセスで実行されることもありません。ANR(アプリケーション応答なし)エラーを回避するには、サービス内の別のスレッドでブロック オペレーションを実行する必要があります。
サービスの種類
サービスには次の 3 種類があります。
- 前景
-
フォアグラウンド サービスは、ユーザーが認識できるオペレーションを実行します。たとえば、オーディオ アプリは、フォアグラウンド サービスを使用して音声トラックを再生します。フォアグラウンド サービスは通知を表示する必要があります。ユーザーがアプリを操作していない場合でも、フォアグラウンド サービスは実行され続けます。
フォアグラウンド サービスを使用する場合は、サービスが実行されていることをユーザーが積極的に認識できるように、通知を表示する必要があります。この通知は、サービスが停止するか、フォアグラウンドから削除されない限り、閉じることはできません。
詳しくは、アプリでフォアグラウンド サービスを設定する方法をご覧ください。
注: WorkManager API を使用すると、柔軟にタスクのスケジュールを設定できます。また、必要に応じてこれらのジョブをフォアグラウンド サービスとして実行できます。多くの場合、フォアグラウンド サービスを直接使用するよりも、WorkManager を使用することをおすすめします。
- 背景
- バックグラウンド サービスが、ユーザーが直接気付かない処理を実行します。たとえば、アプリがサービスを使用してストレージを圧縮した場合、それは通常はバックグラウンド サービスになります。
注: API レベル 26 以降をターゲットとしているアプリの場合、アプリ自体がフォアグラウンドでないときは、バックグラウンド サービスの実行に関する制限が適用されます。たとえば、ほとんどの場合、バックグラウンドで位置情報にアクセスすることは避ける必要があります。代わりに、WorkManager を使用してタスクのスケジュールを設定します。
- バインド
- アプリは、アプリ コンポーネントが
bindService()
を呼び出してサービスにバインドしたときにバインドされます。バインドされたサービスはクライアント サーバー インターフェースを提供します。これにより、コンポーネントがサービスとのやり取り、リクエストの送信、結果の受信に加えて、プロセス間通信(IPC)を使用してプロセス間でも行うことができます。バインドされたサービスは、別のアプリ コンポーネントがバインドされている限り実行されます。複数のコンポーネントを一度にサービスにバインドできますが、すべてのコンポーネントがバインド解除されると、サービスは破棄されます。
このドキュメントでは通常、開始されるサービスとバインドされるサービスを個別に説明しますが、サービスは開始(無期限に実行)することも、バインドすることもできます。重要なのは、複数のコールバック メソッドを実装するかどうかです。onStartCommand()
(コンポーネントが開始できるようにする)と onBind()
(バインディングを許可する)です。
サービスの開始か、バインドされたか、またはその両方かにかかわらず、すべてのアプリ コンポーネントは、任意のコンポーネントがアクティビティを使用できるように、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()
サービス メソッドを作成する方法と、それらを他のアプリ コンポーネントから使用する方法を説明します。
マニフェストでサービスを宣言する
アクティビティやその他のコンポーネントの場合と同様に、すべてのサービスをアプリのマニフェスト ファイルで宣言する必要があります。
サービスを宣言するには、<service>
要素を <application>
要素の子として追加します。次に例を示します。
<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
を渡すことで、サービスを開始できます。サービスはこの Intent
を onStartCommand()
メソッドで受け取ります。
たとえば、アクティビティでオンライン データベースにデータを保存する必要があるとします。アクティビティは、インテントを startService()
に渡すことで、コンパニオン サービスを開始し、保存するデータをアプリに配信できます。サービスは、onStartCommand()
でインテントを受け取り、インターネットに接続して、データベース トランザクションを実行します。トランザクションが完了すると、サービスは自身を停止して破棄されます。
注意: サービスは、宣言されたアプリと同じプロセス内で実行されます。デフォルトでは、そのアプリのメインスレッド内でサービスが実行されます。ユーザーが同じアプリからアクティビティを操作している間に、サービスで集中的なオペレーションやブロッキング オペレーションを実行すると、アクティビティのパフォーマンスが低下します。アプリケーションのパフォーマンスに影響を与えないように、サービス内で新しいスレッドを開始します。
Service
クラスは、すべてのサービスの基本クラスです。このクラスを拡張する際は、サービスがすべての作業を完了できる新しいスレッドを作成することが重要です。サービスはデフォルトでアプリケーションのメインスレッドを使用するため、アプリケーションが実行されているアクティビティのパフォーマンスが低下する可能性があります。
Android フレームワークには、Service
の IntentService
サブクラスも用意されています。このクラスは、ワーカー スレッドを使用して、すべての開始リクエストを 1 つずつ処理します。このクラスの使用は、バックグラウンド実行の制限により Android 8 Oreo 以降では適切に動作しないため、新規アプリではおすすめしません。また、Android 11 以降、サポートは終了しています。JobIntentService を、新しいバージョンの Android と互換性のある IntentService
の代わりとして使用できます。
以下のセクションでは、独自のカスタム サービスを実装する方法について説明しますが、ほとんどのユースケースでは、代わりに 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
と同様に機能し、すべてのリクエストを 1 つずつ順番に処理します。スレッドプールで処理を実行するようにコードを変更できます。たとえば、複数のリクエストを同時に実行したい場合などです。
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()
で配信されるインテントが、アプリ コンポーネントとサービス間の唯一の通信モードになります。ただし、サービスから結果を返す場合、サービスを開始するクライアントは、getBroadcast()
を使用してブロードキャストの PendingIntent
を作成し、サービスを開始する Intent
のサービスに配信できます。その後、サービスはブロードキャストを使用して結果を配信できます。
サービスを開始するリクエストが複数あると、対応するサービスの onStartCommand()
が複数回呼び出されます。ただし、サービスを停止するために必要なリクエスト(stopSelf()
または stopService()
)は 1 つだけです。
サービスの停止
開始したサービスは自身のライフサイクルを管理する必要があります。つまり、システムメモリを回復させる必要があり、onStartCommand()
が返された後もサービスが継続して実行されない限り、システムはサービスを停止または破棄しません。サービスは、stopSelf()
を呼び出して自身を停止する必要があります。または、別のコンポーネントが stopService()
を呼び出してサービスを停止することもできます。
stopSelf()
または stopService()
で停止がリクエストされると、システムは可能な限り早くサービスを破棄します。
サービスが onStartCommand()
に対する複数のリクエストを同時に処理する場合は、開始リクエストの処理完了時にサービスを停止しないでください。新しい開始リクエストを受け取った可能性があるためです(最初のリクエストの終了時に停止すると、2 番目のリクエストが終了します)。この問題を回避するには、stopSelf(int)
を使用して、サービスの停止リクエストが常に最新の開始リクエストに基づいて行われるようにします。つまり、stopSelf(int)
を呼び出すときに、停止リクエストに対応する開始リクエスト(onStartCommand()
に配信される startId
)の ID を渡します。その後、stopSelf(int)
を呼び出せる前にサービスが新しい開始リクエストを受け取った場合、ID が一致せず、サービスは停止しません。
注意: システム リソースを無駄にしたり、バッテリー電力を消費したりしないように、アプリの処理が完了したらサービスを停止してください。必要に応じて、他のコンポーネントが stopService()
を呼び出すことでサービスを停止できます。サービスのバインディングを有効にする場合でも、サービスが onStartCommand()
への呼び出しを受け取った場合は、常にサービスを停止する必要があります。
サービスのライフサイクルの詳細については、以下のサービスのライフサイクルの管理をご覧ください。
バインドされたサービスを作成する
バインドされたサービスとは、bindService()
を呼び出して長時間接続を作成することで、アプリケーション コンポーネントをそのサービスにバインドできるようにするサービスです。通常、コンポーネントが startService()
を呼び出して起動することはできません。
アプリ内のアクティビティや他のコンポーネントからサービスとやり取りする場合や、プロセス間通信(IPC)を介してアプリの機能の一部を他のアプリに公開する場合、バインドされたサービスを作成します。
バインドされたサービスを作成するには、サービスとの通信用のインターフェースを定義する IBinder
を返すように onBind()
コールバック メソッドを実装します。すると、他のアプリ コンポーネントは 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()
によって作成されたサービスが区別されていますが、サービスの開始方法にかかわらず、クライアントがサービスにバインドできる可能性があることに留意してください。クライアントが startService()
を呼び出すために最初に onStartCommand()
で開始したサービスは、引き続き 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()
コールバック メソッドについての詳細を確認できます。