バインドされたサービスは、クライアント サーバー インターフェースにあるサーバーです。バインドされたサービスを使用すると、アクティビティなどのコンポーネントはサービスにバインドし、リクエストの送信、レスポンスの受信、プロセス間通信(IPC)を行えるようになります。通常、バインドされたサービスは他のアプリ コンポーネントにサービスを提供している間だけ機能し、バックグラウンドで無期限に動作することはありません。
このドキュメントでは、バインドされたサービスの作成方法や、他のアプリ コンポーネントからサービスにバインドする方法について説明します。サービスから通知を配信する方法や、フォアグラウンドでサービスを実行するように設定する方法など、サービス全般について詳しくは、サービスのドキュメントをご覧ください。
基本情報
バインドされたサービスは、他のアプリによるバインドとやり取りを可能にする Service
クラスの実装です。サービスのバインドを提供するには、onBind()
コールバック メソッドを実装する必要があります。このメソッドでは IBinder
オブジェクトが返されます。このオブジェクトは、クライアントがサービスとのやり取りに使用できるプログラミング インターフェースを定義します。
開始されたサービスにバインドする
サービスのドキュメントで説明されているように、開始されたサービスとバインドされたサービスの両方を作成できます。つまり、startService()
を呼び出してサービスを開始することでサービスを無期限に実行できるようになります。また、bindService()
を呼び出してクライアントをそのサービスにバインドさせることもできます。
サービスの開始とバインドの両方を許可する場合、サービスが開始されたら、すべてのクライアントがアンバインドされても、システムによってサービスが破棄されることはありません。サービスを停止するには、stopSelf()
または stopService()
を呼び出して明示的に停止する必要があります。
通常、onBind()
か onStartCommand()
のいずれかを実装しますが、両方の実装が必要な場合もあります。たとえば、音楽プレーヤーでは、サービスを無期限に実行しつつ、バインドも提供できると便利な場合があります。この方法であれば、アクティビティがサービスを開始して音楽を再生し、ユーザーがアプリから離れた場合も音楽を再生し続けることができます。その後、ユーザーがアプリに戻ると、アクティビティがサービスにバインドして再生の制御を取り戻すことができます。
開始されたサービスにバインドを追加する際のサービスのライフサイクルについて詳しくは、バインドされたサービスのライフサイクルを管理するをご覧ください。
クライアントがサービスにバインドするには、bindService()
を呼び出します。バインド時は、ServiceConnection
を実装してサービスとの接続を監視する必要があります。bindService()
の戻り値は、リクエストされたサービスが存在するかどうかと、クライアントがそのサービスへのアクセスを許可されているかどうかを示します。Android システムは、クライアントとサービスとの間の接続を作成すると、ServiceConnection
の onServiceConnected()
を呼び出します。onServiceConnected()
メソッドには、IBinder
引数が含まれており、クライアントはこの引数を使用してバインドされたサービスと通信します。
複数のクライアントを 1 つのサービスに同時に接続できます。ただし、システムは IBinder
サービス通信チャネルをキャッシュに保存します。つまり、システムがサービスの onBind()
メソッドを呼び出して IBinder
を生成するのは、最初のクライアントがバインドするときのみです。その後、onBind()
を再度呼び出すことなく、同じサービスにバインドする他のクライアントすべてに同じ IBinder
を配信します。
最後のクライアントがサービスからアンバインドされると、システムはサービスを破棄します(そのサービスが、startService()
によって開始されたサービスでもある場合は除きます)。
バインドされたサービスの実装で最も重要なのは、onBind()
コールバック メソッドが返すインターフェースを定義することです。次のセクションでは、サービスの IBinder
インターフェースを定義する方法について説明します。
バインドされたサービスを作成する
バインドを提供するサービスを作成する際は、IBinder
を提供し、クライアントがサービスとのやり取りに使用できるプログラミング インターフェースを提供する必要があります。インターフェースを定義するには、次の 3 つの方法があります。
- Binder クラスを拡張する
- サービスが独自のアプリ専用であり、クライアントと同じプロセスで実行される場合(ほとんどのケースに該当)、
Binder
クラスを拡張し、そのインスタンスをonBind()
から返すことでインターフェースを作成します。クライアントはBinder
を受け取り、それを使用してBinder
の実装やService
で利用できるパブリック メソッドに直接アクセスできます。サービスが単にアプリのバックグラウンド ワーカーである場合は、この方法が適しています。この方法が適していない唯一のケースは、サービスが他のアプリで使用される場合や、異なるプロセス間で使用される場合です。
- メッセンジャーを使用する
- 異なるプロセス間で動作するインターフェースが必要な場合は、
Messenger
を使用してサービスのインターフェースを作成できます。この方法では、サービスが、異なるタイプのMessage
オブジェクトに応答するHandler
を定義します。このHandler
を基本としてMessenger
はIBinder
をクライアントと共有でき、クライアントはMessage
オブジェクトを使用してサービスにコマンドを送信できるようになります。さらに、クライアントは、サービスがメッセージを返信できるように独自のMessenger
を定義できます。これは、最も簡単にプロセス間通信(IPC)を行う方法であり、
Messenger
がすべてのリクエストを 1 つのスレッドにキューイングするため、サービスをスレッドセーフに設計する必要がありません。 - AIDL を使用する
- Android インターフェース定義言語(AIDL)は、オブジェクトをオペレーティング システムが理解できるプリミティブに分解し、それらをプロセス間でマーシャルすることで IPC を行います。前述の
Messenger
を使用する方法は、実際には AIDL を基本構造としています。前述したように、Messenger
はすべてのクライアント リクエストのキューを 1 つのスレッドに作成するため、サービスはリクエストを一度に 1 つずつ受け取ります。ただし、サービスで複数のリクエストを同時に処理する場合は、AIDL を直接使用できます。この場合、サービスはスレッドセーフであり、かつマルチスレッドに対応している必要があります。AIDL を直接使用するには、プログラミング インターフェースを定義する
.aidl
ファイルを作成する必要があります。Android SDK ツールはこのファイルを使用して、インターフェースを実装して IPC を処理する抽象クラスを生成します。その後、それをサービス内で拡張できます。
注: ほとんどのアプリにおいて、バインドされたサービスを作成する際に AIDL を使用することはおすすめしません。マルチスレッド化が必要になる可能性があり、結果としてより複雑な実装になってしまうためです。AIDL はほとんどのアプリに適していないため、このドキュメントではサービスでの AIDL の使用方法については取り上げません。どうしても AIDL を直接使用する必要がある場合は、AIDL のドキュメントをご覧ください。
Binder クラスを拡張する
サービスがローカルのアプリでのみ使用され、プロセス間での作業が必要ない場合は、クライアントがサービスのパブリック メソッドに直接アクセスできるようにする独自の Binder
クラスを実装できます。
注: この方法は、クライアントとサービスが同じアプリとプロセスにある場合(最も一般的なケース)にのみ有効です。たとえば、バックグラウンドで音楽を再生する独自のサービスにアクティビティをバインドする必要がある音楽アプリに適しています。
設定手順は次のとおりです。
- サービスで、次のいずれかを行う
Binder
のインスタンスを作成します。- クライアントが呼び出せるパブリック メソッドを格納する。
- クライアントが呼び出せるパブリック メソッドがある、現在の
Service
インスタンスを返す。 - クライアントが呼び出せるパブリック メソッドを含む、サービスでホストされた他のクラスのインスタンスを返す。
Binder
のインスタンスをonBind()
コールバック メソッドから返します。- クライアントで
Binder
をonServiceConnected()
コールバック メソッドから受け取り、提供されたメソッドを使用して、バインドされたサービスを呼び出します。
注: クライアントが返されたオブジェクトをキャストし、その API を適切に呼び出すことができるように、サービスとクライアントは同じアプリ内にある必要があります。また、この方法ではプロセス間のマーシャルが行われないため、サービスとクライアントは同じプロセス内にもある必要があります。
Binder
の実装を介してサービスのメソッドへのアクセスをクライアントに提供するサービスの例を次に示します。
Kotlin
class LocalService : Service() { // Binder given to clients private val binder = LocalBinder() // Random number generator private val mGenerator = Random() /** method for clients */ val randomNumber: Int get() = mGenerator.nextInt(100) /** * Class used for the client Binder. Because we know this service always * runs in the same process as its clients, we don't need to deal with IPC. */ inner class LocalBinder : Binder() { // Return this instance of LocalService so clients can call public methods fun getService(): LocalService = this@LocalService } override fun onBind(intent: Intent): IBinder { return binder } }
Java
public class LocalService extends Service { // Binder given to clients private final IBinder binder = new LocalBinder(); // Random number generator private final Random mGenerator = new Random(); /** * Class used for the client Binder. Because we know this service always * runs in the same process as its clients, we don't need to deal with IPC. */ public class LocalBinder extends Binder { LocalService getService() { // Return this instance of LocalService so clients can call public methods return LocalService.this; } } @Override public IBinder onBind(Intent intent) { return binder; } /** method for clients */ public int getRandomNumber() { return mGenerator.nextInt(100); } }
LocalBinder
が LocalService
の現在のインスタンスを取得するための getService()
メソッドをクライアントに提供します。これにより、クライアントがサービスのパブリック メソッドを呼び出せるようになります。たとえば、クライアントはサービスから getRandomNumber()
を呼び出せます。
ボタンがクリックされたときに LocalService
にバインドして、getRandomNumber()
を呼び出すアクティビティの例を次に示します。
Kotlin
class BindingActivity : Activity() { private lateinit var mService: LocalService private var mBound: Boolean = false /** Defines callbacks for service binding, passed to bindService() */ private val connection = object : ServiceConnection { override fun onServiceConnected(className: ComponentName, service: IBinder) { // We've bound to LocalService, cast the IBinder and get LocalService instance val binder = service as LocalService.LocalBinder mService = binder.getService() mBound = true } override fun onServiceDisconnected(arg0: ComponentName) { mBound = false } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.main) } override fun onStart() { super.onStart() // Bind to LocalService Intent(this, LocalService::class.java).also { intent -> bindService(intent, connection, Context.BIND_AUTO_CREATE) } } override fun onStop() { super.onStop() unbindService(connection) mBound = false } /** Called when a button is clicked (the button in the layout file attaches to * this method with the android:onClick attribute) */ fun onButtonClick(v: View) { if (mBound) { // Call a method from the LocalService. // However, if this call were something that might hang, then this request should // occur in a separate thread to avoid slowing down the activity performance. val num: Int = mService.randomNumber Toast.makeText(this, "number: $num", Toast.LENGTH_SHORT).show() } } }
Java
public class BindingActivity extends Activity { LocalService mService; boolean mBound = false; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } @Override protected void onStart() { super.onStart(); // Bind to LocalService Intent intent = new Intent(this, LocalService.class); bindService(intent, connection, Context.BIND_AUTO_CREATE); } @Override protected void onStop() { super.onStop(); unbindService(connection); mBound = false; } /** Called when a button is clicked (the button in the layout file attaches to * this method with the android:onClick attribute) */ public void onButtonClick(View v) { if (mBound) { // Call a method from the LocalService. // However, if this call were something that might hang, then this request should // occur in a separate thread to avoid slowing down the activity performance. int num = mService.getRandomNumber(); Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show(); } } /** Defines callbacks for service binding, passed to bindService() */ private ServiceConnection connection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName className, IBinder service) { // We've bound to LocalService, cast the IBinder and get LocalService instance LocalBinder binder = (LocalBinder) service; mService = binder.getService(); mBound = true; } @Override public void onServiceDisconnected(ComponentName arg0) { mBound = false; } }; }
上記の例は、ServiceConnection
の実装と onServiceConnected()
コールバックを使用してクライアントがサービスにバインドする方法を示しています。次のセクションでは、サービスへのバインドのプロセスについて詳しく説明します。
注: 上記の例では、onStop()
メソッドがクライアントをサービスからアンバインドしています。その他の注意事項で説明されているように、クライアントは適切なタイミングでサービスからアンバインドする必要があります。
他のサンプルコードについては、ApiDemos の LocalService.java
クラスと、LocalServiceActivities.java
クラスをご覧ください。
メッセンジャーを使用する
リモート プロセスと通信するサービスが必要な場合は、Messenger
を使用してサービスのインターフェースを提供できます。この方法では、AIDL を使用しなくてもプロセス間通信(IPC)を行えます。
Messenger
はサービスに対するすべての呼び出しをキューイングするため、インターフェースに Messenger
を使用する方が、AIDL を使用するよりも簡単です。純粋な AIDL インターフェースは複数のリクエストを同時にサービスに送信するため、サービスはマルチスレッドを処理する必要があります。
ほとんどのアプリでは、サービスはマルチスレッドを実行する必要がないため、Messenger
を使用することで、サービスが一度に 1 つの呼び出しを処理できます。サービスのマルチスレッド化が重要である場合は、AIDL を使用してインターフェースを定義してください。
Messenger
の使用方法の概要は次のとおりです。
- サービスが、クライアントからの呼び出しごとにコールバックを受け取る
Handler
を実装します。 - サービスが、
Handler
を使用してMessenger
オブジェクト(Handler
への参照)を作成します。 Messenger
は、サービスがonBind()
からクライアントに返すIBinder
を作成します。- クライアントが
IBinder
を使用して、サービスのHandler
を参照するMessenger
をインスタンス化します。クライアントはこれを使用してMessage
オブジェクトをサービスに送信します。 - サービスが、その
Handler
(具体的にはhandleMessage()
メソッド)でそれぞれのMessage
を受け取ります。
この方法には、クライアントがサービスで呼び出すメソッドはありません。代わりに、クライアントは、サービスがその Handler
で受け取るメッセージ(Message
オブジェクト)を配信します。
Messenger
インターフェースを使用するサービスの簡単な例を次に示します。
Kotlin
/** Command to the service to display a message */ private const val MSG_SAY_HELLO = 1 class MessengerService : Service() { /** * Target we publish for clients to send messages to IncomingHandler. */ private lateinit var mMessenger: Messenger /** * Handler of incoming messages from clients. */ internal class IncomingHandler( context: Context, private val applicationContext: Context = context.applicationContext ) : Handler() { override fun handleMessage(msg: Message) { when (msg.what) { MSG_SAY_HELLO -> Toast.makeText(applicationContext, "hello!", Toast.LENGTH_SHORT).show() else -> super.handleMessage(msg) } } } /** * When binding to the service, we return an interface to our messenger * for sending messages to the service. */ override fun onBind(intent: Intent): IBinder? { Toast.makeText(applicationContext, "binding", Toast.LENGTH_SHORT).show() mMessenger = Messenger(IncomingHandler(this)) return mMessenger.binder } }
Java
public class MessengerService extends Service { /** * Command to the service to display a message */ static final int MSG_SAY_HELLO = 1; /** * Handler of incoming messages from clients. */ static class IncomingHandler extends Handler { private Context applicationContext; IncomingHandler(Context context) { applicationContext = context.getApplicationContext(); } @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_SAY_HELLO: Toast.makeText(applicationContext, "hello!", Toast.LENGTH_SHORT).show(); break; default: super.handleMessage(msg); } } } /** * Target we publish for clients to send messages to IncomingHandler. */ Messenger mMessenger; /** * When binding to the service, we return an interface to our messenger * for sending messages to the service. */ @Override public IBinder onBind(Intent intent) { Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show(); mMessenger = new Messenger(new IncomingHandler(this)); return mMessenger.getBinder(); } }
Handler
の handleMessage()
メソッドは、サービスが Message
を受け取り、what
メンバーに基づいてその後の操作を決めるための要素であることに注目してください。
クライアントで必要な操作は、サービスから返された IBinder
に基づいて Messenger
を作成し、send()
を使用してメッセージを送信することだけです。例として、サービスにバインドして MSG_SAY_HELLO
メッセージをサービスに配信する簡単なアクティビティを次に示します。
Kotlin
class ActivityMessenger : Activity() { /** Messenger for communicating with the service. */ private var mService: Messenger? = null /** Flag indicating whether we have called bind on the service. */ private var bound: Boolean = false /** * Class for interacting with the main interface of the service. */ private val mConnection = object : ServiceConnection { override fun onServiceConnected(className: ComponentName, service: IBinder) { // This is called when the connection with the service has been // established, giving us the object we can use to // interact with the service. We are communicating with the // service using a Messenger, so here we get a client-side // representation of that from the raw IBinder object. mService = Messenger(service) bound = true } override fun onServiceDisconnected(className: ComponentName) { // This is called when the connection with the service has been // unexpectedly disconnected -- that is, its process crashed. mService = null bound = false } } fun sayHello(v: View) { if (!bound) return // Create and send a message to the service, using a supported 'what' value val msg: Message = Message.obtain(null, MSG_SAY_HELLO, 0, 0) try { mService?.send(msg) } catch (e: RemoteException) { e.printStackTrace() } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.main) } override fun onStart() { super.onStart() // Bind to the service Intent(this, MessengerService::class.java).also { intent -> bindService(intent, mConnection, Context.BIND_AUTO_CREATE) } } override fun onStop() { super.onStop() // Unbind from the service if (bound) { unbindService(mConnection) bound = false } } }
Java
public class ActivityMessenger extends Activity { /** Messenger for communicating with the service. */ Messenger mService = null; /** Flag indicating whether we have called bind on the service. */ boolean bound; /** * Class for interacting with the main interface of the service. */ private ServiceConnection mConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { // This is called when the connection with the service has been // established, giving us the object we can use to // interact with the service. We are communicating with the // service using a Messenger, so here we get a client-side // representation of that from the raw IBinder object. mService = new Messenger(service); bound = true; } public void onServiceDisconnected(ComponentName className) { // This is called when the connection with the service has been // unexpectedly disconnected -- that is, its process crashed. mService = null; bound = false; } }; public void sayHello(View v) { if (!bound) return; // Create and send a message to the service, using a supported 'what' value Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0); try { mService.send(msg); } catch (RemoteException e) { e.printStackTrace(); } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } @Override protected void onStart() { super.onStart(); // Bind to the service bindService(new Intent(this, MessengerService.class), mConnection, Context.BIND_AUTO_CREATE); } @Override protected void onStop() { super.onStop(); // Unbind from the service if (bound) { unbindService(mConnection); bound = false; } } }
この例では、サービスがクライアントにどのように応答できるのかは示されていません。サービスに応答させるには、クライアントで Messenger
も作成する必要があります。クライアントは onServiceConnected()
コールバックを受け取ると、send()
メソッドの replyTo
パラメータにクライアントの Messenger
を含めた Message
をサービスに送信します。
双方向メッセージを提供する方法の例については、MessengerService.java
(サービス)と MessengerServiceActivities.java
(クライアント)のサンプルをご覧ください。
サービスにバインドする
アプリ コンポーネント(クライアント)がサービスにバインドする際は、bindService()
を呼び出します。Android システムがサービスの onBind()
メソッドを呼び出し、そこからサービスとのやり取りに必要な IBinder
が返されます。
バインドは非同期的に行われます。bindService()
は IBinder
をクライアントに返すことなく、すぐに戻ります。IBinder
を受け取るには、クライアントが ServiceConnection
のインスタンスを作成し、それを bindService()
に渡す必要があります。ServiceConnection
には、システムが IBinder
を配信するために呼び出すコールバック メソッドが含まれています。
注: サービスにバインドできるのは、アクティビティ、サービス、コンテンツ プロバイダのみです。ブロードキャスト レシーバからサービスにバインドすることはできません。
クライアントからサービスにバインドする手順は、次のとおりです。
ServiceConnection
を実装します。実装では次の 2 つのコールバック メソッドをオーバーライドする必要があります。
onServiceConnected()
- システムがこのメソッドを呼び出して、サービスの
onBind()
メソッドから返されたIBinder
を配信します。 onServiceDisconnected()
- サービスのクラッシュや強制終了があった場合など、サービスへの接続が予期せず失われたときに、Android システムはこのメソッドを呼び出します。このメソッドは、クライアントのアンバインドの際には呼び出されません。
bindService()
を呼び出して、ServiceConnection
の実装を渡します。注: このメソッドから false が返された場合、クライアントにはサービスへの有効な接続がありません。ただし、クライアントはそれでも
unbindService()
を呼び出す必要があります。そうしないと、サービスがアイドル状態でも、シャットダウンされなくなります。- システムが
onServiceConnected()
コールバック メソッドを呼び出すと、インターフェースで定義されたメソッドを使用してサービスへの呼び出しを開始できます。 - サービスとの接続を切断するには、
unbindService()
を呼び出します。アプリによってクライアントが破棄されたときに、クライアントが引き続きサービスにバインドされている場合は、この破棄によりクライアントがアンバインドされます。クライアントがサービスとのやり取りを完了した直後に、クライアントをアンバインドすることをおすすめします。このようにすると、アイドル状態のサービスをシャットダウンできます。バインドとアンバインドの適切なタイミングについては、その他の注意事項をご覧ください。
次の例では、Binder クラスを拡張して上記で作成したサービスにクライアントを接続しているため、必要な処理は、返された IBinder
を LocalBinder
クラスにキャストして、LocalService
インスタンスをリクエストすることだけです。
Kotlin
var mService: LocalService val mConnection = object : ServiceConnection { // Called when the connection with the service is established override fun onServiceConnected(className: ComponentName, service: IBinder) { // Because we have bound to an explicit // service that is running in our own process, we can // cast its IBinder to a concrete class and directly access it. val binder = service as LocalService.LocalBinder mService = binder.getService() mBound = true } // Called when the connection with the service disconnects unexpectedly override fun onServiceDisconnected(className: ComponentName) { Log.e(TAG, "onServiceDisconnected") mBound = false } }
Java
LocalService mService; private ServiceConnection mConnection = new ServiceConnection() { // Called when the connection with the service is established public void onServiceConnected(ComponentName className, IBinder service) { // Because we have bound to an explicit // service that is running in our own process, we can // cast its IBinder to a concrete class and directly access it. LocalBinder binder = (LocalBinder) service; mService = binder.getService(); mBound = true; } // Called when the connection with the service disconnects unexpectedly public void onServiceDisconnected(ComponentName className) { Log.e(TAG, "onServiceDisconnected"); mBound = false; } };
この ServiceConnection
を使用して、次の例のように、クライアントはそれを bindService()
に渡すことでサービスにバインドできます。
Kotlin
Intent(this, LocalService::class.java).also { intent -> bindService(intent, connection, Context.BIND_AUTO_CREATE) }
Java
Intent intent = new Intent(this, LocalService.class); bindService(intent, connection, Context.BIND_AUTO_CREATE);
bindService()
の最初のパラメータは、バインドするサービス名を明示的に指定するIntent
です。注:
Service
へのバインドにインテントを使用する場合は、明示的インテントを使用して、アプリを確実にセキュアにするようにしてください。暗黙的インテントを使用してサービスを開始すると、どのサービスがインテントに応答するのかを把握できず、ユーザーにはどのサービスが開始するのかがわからないため、セキュリティ上の危険が伴います。Android 5.0(API レベル 21)以降では、暗黙的インテントを使用してbindService()
を呼び出すと、システムから例外がスローされます。- 2 つ目のパラメータは、
ServiceConnection
オブジェクトです。 - 3 つ目のパラメータはバインドのオプションを示すフラグです。通常は
BIND_AUTO_CREATE
に設定して、サービスがまだ存在していない場合にはサービスを作成するようにします。他の有効な値はBIND_DEBUG_UNBIND
とBIND_NOT_FOREGROUND
です。何も指定しない場合は0
に設定します。
その他の注意事項
サービスへのバインドに関する重要な注意点は次のとおりです。
- 接続が切れたときにスローされる
DeadObjectException
例外は、常にトラップする必要があります。リモート メソッドからスローされる例外はこれのみです。 - オブジェクトはプロセス間で有効な参照です。
- 通常は、クライアントのライフサイクルの開始と終了のタイミングに合わせて、その間でバインドとアンバインドをペア設定します。次の例をご覧ください。
- アクティビティが見えている間のみサービスとやり取りする必要がある場合は、
onStart()
の間にバインドし、onStop()
の間にアンバインドします。 - アクティビティがバックグラウンドで停止している間も応答を受け取るようにする場合は、
onCreate()
の間にバインドし、onDestroy()
の間にアンバインドします。つまり、アクティビティの実行中(バックグラウンドも含む)は常にサービスを使用する必要があるため、サービスが別のプロセスにある場合は、プロセスの重みを上げて、システムに強制終了させやすいようにします。
注: アクティビティの
onResume()
とonPause()
の間にはバインドとアンバインドを行いません。これらのコールバックはすべてのライフサイクル遷移で発生し、その遷移で発生するプロセスを最小限に抑える必要があるためです。また、アプリの複数のアクティビティが同一サービスにバインドしていて、その中の 2 つのアクティビティ間で遷移が生じる場合、現在のアクティビティは、次のアクティビティが(再開中に)バインドされる前に(停止中に)アンバインドされるため、サービスが破棄されて再作成されることがあります。ライフサイクルと連携したアクティビティの遷移について詳しくは、アクティビティのドキュメントをご覧ください。 - アクティビティが見えている間のみサービスとやり取りする必要がある場合は、
他のサンプルコードについては、ApiDemos の RemoteService.java
クラスをご覧ください。
バインドされたサービスのライフサイクルを管理する
サービスがすべてのクライアントからアンバインドされると、Android システムがそれを破棄します(startService()
で開始されたサービスでもある場合を除く)。純粋にバインドされたサービスであれば、サービスのライフサイクルを管理する必要はありません。サービスがクライアントにバインドされているかどうかに基づいて Android システムがライフサイクルを管理します。
ただし、onStartCommand()
コールバック メソッドを実装する場合、そのサービスは「開始されたサービス」とみなされるため、サービスを明示的に停止する必要があります。この場合、クライアントにバインドされているかどうかにかかわらず、サービスが stopSelf()
で自ら停止するか、他のコンポーネントが stopService()
を呼び出すまで、サービスは動作し続けます。
さらに、サービスが開始されてバインドを許可する場合、システムが onUnbind()
メソッドを呼び出す際に、次回クライアントがサービスにバインドするときに onRebind()
への呼び出しを受け取りたい場合は true
を返すようにすることもできます。onRebind()
からは void が返されますが、クライアントは onServiceConnected()
コールバックで IBinder
を受け取ります。次の図は、この種類のライフサイクルのロジックを示しています。

図 1. 開始されたサービスでバインドも許可する場合のサービスのライフサイクル。
開始されたサービスのライフサイクルについて詳しくは、サービスのドキュメントをご覧ください。