バインドされたサービスの概要

バインドされたサービスは、クライアント サーバー インターフェースにあるサーバーです。これにより、アクティビティなどのコンポーネントがサービスへのバインド、リクエストの送信、レスポンスの受信、プロセス間通信(IPC)の実行を行えるようになります。通常、バインドされたサービスは他のアプリ コンポーネントにサービスを提供している間だけ機能し、バックグラウンドで無期限に動作することはありません。

このドキュメントでは、バインドされたサービスの作成方法や、他のアプリ コンポーネントからサービスにバインドする方法について説明します。サービスから通知を配信する方法や、サービスをフォアグラウンドで実行する方法など、サービスの一般的な詳細については、 サービスの概要をご覧ください。

基本情報

バインドされたサービスは Service クラスの実装であり、他のアプリがこのサービスにバインドしてやり取りできるようにします。サービスのバインディングを提供するには、onBind() コールバック メソッドを実装します。このメソッドでは IBinder オブジェクトが返されます。このオブジェクトは、クライアントがサービスとのやり取りに使用できるプログラミング インターフェースを定義します。

開始されたサービスにバインドする

サービスの概要で説明したように、開始されるサービスとバインドされるサービスの両方を作成できます。つまり、startService() を呼び出してサービスを開始すると、サービスを無期限に実行できます。bindService() を呼び出すことで、クライアントがサービスにバインドすることもできます。

サービスを開始してバインドした場合、サービスの開始時にすべてのクライアントのバインド解除が行われても、システムはサービスを破棄しません。サービスを停止するには、stopSelf() または stopService() を呼び出して明示的に停止する必要があります。

通常、onBind()onStartCommand() のいずれかを実装しますが、両方の実装が必要な場合もあります。たとえば、音楽プレーヤーでは、サービスを無期限に実行し、バインディングも提供すると便利な場合があります。これにより、アクティビティがサービスを開始して音楽を再生し、ユーザーがアプリを離れても音楽の再生を継続できます。その後、ユーザーがアプリに戻ると、アクティビティがサービスにバインドして再生の制御を取り戻すことができます。

開始されたサービスにバインドを追加する際のサービスのライフサイクルの詳細については、バインドされたサービスのライフサイクルを管理するをご覧ください。

クライアントがサービスにバインドするには、bindService() を呼び出します。バインド時は、ServiceConnection を実装してサービスとの接続を監視する必要があります。bindService() の戻り値は、リクエストされたサービスが存在するかどうかと、クライアントがそのサービスへのアクセスを許可されているかどうかを示します。

Android システムは、クライアントとサービス間の接続を作成すると、ServiceConnectiononServiceConnected() を呼び出します。onServiceConnected() メソッドには IBinder 引数が含まれます。クライアントはこの引数を使用して、バインドされたサービスと通信します。

複数のクライアントを 1 つのサービスに同時に接続できます。ただし、システムは IBinder サービス通信チャネルをキャッシュに保存します。つまり、最初のクライアントがバインドされるときにのみ、サービスの onBind() メソッドを呼び出して IBinder が生成されます。その後、onBind() を再度呼び出すことなく、同じサービスにバインドする他のクライアントすべてに同じ IBinder を配信します。

最後のクライアントがサービスからバインド解除されると、システムはサービスを破棄します(startService() を使用してサービスが開始された場合を除きます)。

バインドされたサービスの実装で最も重要なのは、onBind() コールバック メソッドが返すインターフェースを定義することです。次のセクションでは、サービスの IBinder インターフェースを定義する方法について説明します。

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

バインドを提供するサービスを作成する際は、IBinder を提供し、クライアントがサービスとのやり取りに使用できるプログラミング インターフェースを提供する必要があります。インターフェースを定義するには、次の 3 つの方法があります。

Binder クラスを拡張する
サービスが独自のアプリに非公開で、クライアントと同じプロセスで実行される場合は(よくあることです)、Binder クラスを拡張して onBind() からそのインスタンスを返すことにより、インターフェースを作成します。クライアントは Binder を受け取り、それを使用して Binder の実装や Service で利用できるパブリック メソッドに直接アクセスできます。

サービスが単にアプリのバックグラウンド ワーカーである場合は、この方法が適しています。この方法がインターフェース作成の推奨方法ではない唯一のユースケースは、そのサービスが他のアプリや個別のプロセスで使用されている場合です。

メッセンジャーを使用する
異なるプロセス間で動作するインターフェースが必要な場合は、Messenger を使用してサービスのインターフェースを作成できます。このようにして、サービスは異なるタイプの Message オブジェクトに応答する Handler を定義します。

この Handler は、IBinder をクライアントと共有し、クライアントが Message オブジェクトを使用してサービスにコマンドを送信できるようにする Messenger の基礎となります。また、クライアントは独自の Messenger を定義して、サービスがメッセージを返送することもできます。

これは、最も簡単にプロセス間通信(IPC)を行う方法であり、Messenger がすべてのリクエストを 1 つのスレッドにキューイングするため、サービスをスレッドセーフに設計する必要がありません。

AIDL を使用する
Android インターフェース定義言語(AIDL)は、オペレーティング システムが理解可能なプリミティブにオブジェクトを分解し、プロセス間でそれらをマーシャリングして IPC を実行します。Messenger を使用する前述の手法は、実際には AIDL を基本構造としてベースとしています。

前のセクションで説明したように、Messenger はすべてのクライアント リクエストのキューを 1 つのスレッドに作成するため、サービスは一度に 1 つずつリクエストを受信します。ただし、サービスで複数のリクエストを同時に処理する場合は、AIDL を直接使用できます。この場合、サービスはスレッドセーフで、マルチスレッド処理に対応する必要があります。

AIDL を直接使用するには、プログラミング インターフェースを定義する .aidl ファイルを作成します。Android SDK ツールはこのファイルを使用して、インターフェースを実装して IPC を処理する抽象クラスを生成します。その後、それをサービス内で拡張できます。

注: ほとんどのアプリにおいて、AIDL はバインドされたサービスの作成に最適ではありません。これは、マルチスレッド機能が必要になることがあり、実装がより複雑になる可能性があるためです。このため、このドキュメントでは、サービスをサービスで使用する方法については説明しません。AIDL を直接使用する必要がある場合は、AIDL のドキュメントをご覧ください。

Binder クラスを拡張する

ローカル アプリケーションのみがサービスを使用し、プロセス間で動作する必要がない場合は、独自の Binder クラスを実装して、サービスのパブリック メソッドへのクライアント アクセスを直接提供できます。

注: この方法は、クライアントとサービスが同じアプリとプロセスにある場合(最も一般的なケース)にのみ有効です。たとえば、バックグラウンドで音楽を再生する独自のサービスにアクティビティをバインドする必要がある音楽アプリに適しています。

設定手順は次のとおりです。

  1. サービスで、次のいずれかを行う Binder のインスタンスを作成します。
    • クライアントが呼び出せるパブリック メソッドを格納する。
    • クライアントが呼び出せるパブリック メソッドがある、現在の Service インスタンスを返す。
    • クライアントが呼び出せるパブリック メソッドを含む、サービスでホストされた他のクラスのインスタンスを返す。
  2. Binder のインスタンスを onBind() コールバック メソッドから返します。
  3. クライアントで BinderonServiceConnected() コールバック メソッドから受け取り、提供されたメソッドを使用して、バインドされたサービスを呼び出します。

注: クライアントが返されたオブジェクトをキャストし、その 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);
    }
}

LocalBinderLocalService の現在のインスタンスを取得するための 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 is something that might hang, then put this request
            // 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 is something that might hang, then put this request
            // 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() メソッドはクライアントをサービスからバインド解除しています。その他の情報セクションの説明に沿って、適切なタイミングでクライアントをサービスからバインド解除します。

他のサンプルコードについては、ApiDemosLocalService.java クラスと、LocalServiceActivities.java クラスをご覧ください。

メッセンジャーを使用する

リモート プロセスと通信するサービスが必要な場合は、Messenger を使用してサービスのインターフェースを提供できます。この方法では、AIDL を使用することなくプロセス間通信(IPC)を実行できます。

Messenger はサービスに対するすべての呼び出しをキューイングするため、インターフェースに Messenger を使用する方が、AIDL を使用するよりも簡単です。純粋な AIDL インターフェースがサービスに同時リクエストを送信し、サービスはマルチスレッド処理を処理する必要があります。

ほとんどのアプリケーションでは、サービスでマルチスレッド処理を実行する必要がないため、Messenger を使用することで、一度に 1 つの呼び出しを処理できます。サービスをマルチスレッド化することが重要な場合は、AIDL を使用してインターフェースを定義します。

Messenger の使用方法の概要は次のとおりです。

  1. サービスが、クライアントからの呼び出しごとにコールバックを受け取る Handler を実装します。
  2. サービスが、Handler を使用して Messenger オブジェクト(Handler への参照)を作成します。
  3. Messenger は、サービスが onBind() からクライアントに返す IBinder を作成します。
  4. クライアントが IBinder を使用して、サービスの Handler を参照する Messenger をインスタンス化します。クライアントはこれを使用して Message オブジェクトをサービスに送信します。
  5. サービスが、その 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();
    }
}

HandlerhandleMessage() メソッドでは、サービスが着信した 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 を配信するために呼び出すコールバック メソッドが含まれています。

注: サービスにバインドできるのは、アクティビティ、サービス、コンテンツ プロバイダのみです。ブロードキャスト レシーバからサービスにバインドすることはできません。

クライアントからサービスにバインドする手順は、次のとおりです。

  1. ServiceConnection を実装します。

    実装では次の 2 つのコールバック メソッドをオーバーライドする必要があります。

    onServiceConnected()
    システムがこのメソッドを呼び出して、サービスの onBind() メソッドから返された IBinder を配信します。
    onServiceDisconnected()
    サービスがクラッシュまたは強制終了されたときなど、サービスへの接続が予期せず失われたときに、Android システムがこれを呼び出します。このメソッドは、クライアントのアンバインドの際には呼び出されません。
  2. bindService() を呼び出して、ServiceConnection の実装を渡します。

    注: このメソッドから false が返された場合、クライアントにはサービスへの有効な接続がありません。ただし、クライアントで unbindService() を呼び出してください。そうしないと、クライアントはサービスがアイドル状態のときにシャットダウンしないようにします。

  3. システムが onServiceConnected() コールバック メソッドを呼び出すと、インターフェースで定義されたメソッドを使用してサービスへの呼び出しを開始できます。
  4. サービスとの接続を切断するには、unbindService() を呼び出します。

    アプリによってクライアントが破棄されたときに、クライアントが引き続きサービスにバインドされている場合は、この破棄によりクライアントがアンバインドされます。サービスとのやり取りが完了したら、すぐにクライアントをバインド解除することをおすすめします。これにより、アイドル状態のサービスをシャットダウンできます。バインドとバインド解除の適切なタイミングについては、その他の情報セクションをご覧ください。

次の例では、Binder クラスを拡張して、以前に作成したサービスにクライアントを接続するため、必要なのは、返された IBinderLocalBinder クラスにキャストして、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_UNBINDBIND_NOT_FOREGROUND、なしの場合は 0 です。

その他の注意事項

サービスへのバインドに関する重要な注意点は次のとおりです。

  • 接続が切断されたときにスローされる DeadObjectException 例外を常にトラップします。リモート メソッドからスローされる例外はこれのみです。
  • オブジェクトはプロセス間で有効な参照です。
  • 通常、次の例に示すように、クライアントのライフサイクルの立ち上げと破棄が一致するタイミングで、バインディングとバインド解除をペア設定します。
    • アクティビティが表示されている間だけサービスを操作する必要がある場合は、onStart() の間にバインドし、onStop() の間にバインドを解除します。
    • アクティビティがバックグラウンドで停止している場合でもレスポンスを受け取るようにするには、onCreate() 中にバインドし、onDestroy() 中にバインドを解除します。これは、アクティビティの実行中に(バックグラウンドであっても)サービスがサービスを使用する必要があることを意味するため、サービスが別のプロセスにある場合はプロセスの重みが増加し、システムによって強制終了される可能性が高くなります。

    注: 通常、アクティビティの onResume() コールバックと onPause() コールバックは、バインドとアンバインドを行いません。これは、これらのコールバックはライフサイクルの遷移のたびに発生するためです。これらの移行で発生する処理は最小限に抑えます。

    また、アプリの複数のアクティビティが同じサービスにバインドしていて、2 つのアクティビティ間で遷移が発生する場合、次のアクティビティがバインドされる前に(再開時)現在のアクティビティがバインド解除されるときに(一時停止時に)サービスが破棄され、再作成される可能性があります。アクティビティがライフサイクルを調整する仕組みに関するこのアクティビティの遷移については、アクティビティのライフサイクルで説明しています。

サービスにバインドする方法を示すサンプルコードについては、ApiDemos RemoteService.java クラスをご覧ください。

バインドされたサービスのライフサイクルを管理する

サービスがすべてのクライアントからバインド解除されると、Android システムはそのサービスを破棄します(startService() を使用して開始された場合を除く)。したがって、純粋にバインドされたサービスであれば、サービスのライフサイクルを管理する必要はありません。Android システムは、クライアントにバインドされているかどうかに基づいて管理します。

ただし、onStartCommand() コールバック メソッドを実装する場合は、サービスが開始されたとみなされるため、サービスを明示的に停止する必要があります。この場合、クライアントにバインドされているかどうかにかかわらず、サービスが stopSelf() で自ら停止するか、他のコンポーネントが stopService() を呼び出すまで、サービスは動作し続けます。

また、サービスが起動してバインディングを受け入れた場合、次回クライアントがサービスにバインドしたときに onRebind() の呼び出しを受け取れるように、システムが onUnbind() メソッドを呼び出すときに必要に応じて true を返すことができます。onRebind() からは void が返されますが、クライアントは onServiceConnected() コールバックで IBinder を受け取ります。次の図は、この種類のライフサイクルのロジックを示しています。

図 1. 開始されたサービスでバインドも許可する場合のサービスのライフサイクル。

開始されたサービスのライフサイクルの詳細については、サービスの概要をご覧ください。