Общие сведения о привязанных сервисах

Привязанная служба – это сервер в интерфейсе "клиент – сервер". Она позволяет компонентам, например действиям, связываться с сервисом, отправлять запросы, получать ответы и выполнять межпроцессное взаимодействие (IPC). Обычно привязанная служба существует, только пока обслуживает другой компонент приложения, и не работает в фоновом режиме постоянно.

В этом документе описывается, как создать привязанную службу и как привязать ее к другим компонентам приложения. Дополнительную информацию о сервисах в целом, например о том, как доставлять уведомления из сервиса и настроить его запуск в активном режиме, можно найти в обзоре сервисов.

Основные сведения

Привязанная служба – это реализация класса Service, которая позволяет другим приложениям привязываться к ней и взаимодействовать с ней. Чтобы обеспечить привязку к сервису, реализуйте метод обратного вызова onBind(). Этот метод возвращает объект IBinder, который определяет программный интерфейс, используемый клиентами для взаимодействия с сервисом.

Привязка к запущенному сервису

Как описано в обзоре сервисов, вы можете создать сервис, который будет одновременно запущенным и привязанным. Это означает, что вы можете запустить сервис, вызвав метод startService(), и он будет работать неограниченное время. Вы также можете разрешить клиенту привязку к сервису, вызвав bindService().

Если вы разрешите запуск и привязку сервиса, то при его запуске система не уничтожит сервис, когда все клиенты отвяжутся. Вместо этого необходимо явно остановить сервис, вызвав stopSelf() или stopService().

Хотя обычно вы реализуете либо onBind(), либо onStartCommand(), иногда необходимо реализовать оба варианта. Например, для музыкального проигрывателя может быть полезно, чтобы его служба работала неограниченно долго, а также обеспечивала привязку. Таким образом, действие может запустить службу для воспроизведения музыки, и музыка будет продолжать играть, даже если пользователь выйдет из приложения. Когда пользователь возвращается в приложение, действие может привязаться к сервису, чтобы восстановить управление воспроизведением.

Дополнительную информацию о жизненном цикле службы при добавлении привязки к запущенной службе можно найти в разделе Управление жизненным циклом привязанной службы.

Клиент привязывается к сервису, вызывая метод bindService(). При этом необходимо реализовать интерфейс ServiceConnection, который отслеживает подключение к сервису. Возвращаемое значение bindService() указывает, существует ли запрашиваемый сервис и разрешен ли клиенту доступ к нему.

Когда система Android создает подключение между клиентом и сервисом, она вызывает метод onServiceConnected() в объекте ServiceConnection. Метод onServiceConnected() включает аргумент IBinder, который клиент использует для связи с привязанной службой.

К сервису можно подключить несколько клиентов одновременно. Однако система кеширует канал связи сервиса IBinder. Другими словами, система вызывает метод onBind() сервиса для создания IBinder только тогда, когда привязывается первый клиент. Затем система доставляет этот же объект IBinder всем дополнительным клиентам, которые привязываются к тому же сервису, не вызывая onBind() снова.

Когда последний клиент отключается от сервиса, система удаляет сервис, если он не был запущен с помощью startService().

Самая важная часть реализации привязанной службы – определение интерфейса, который возвращает метод обратного вызова onBind(). В следующем разделе рассматриваются несколько способов определения интерфейса IBinder вашего сервиса.

Как создать привязанную службу

При создании сервиса, который предоставляет привязку, необходимо предоставить объект IBinder, который предоставляет программный интерфейс, используемый клиентами для взаимодействия с сервисом. Определить интерфейс можно тремя способами:

Расширение класса Binder
Если сервис является частным для вашего приложения и выполняется в том же процессе, что и клиент (это распространенный случай), создайте интерфейс, расширив класс Binder и возвратив его экземпляр из метода onBind(). Клиент получает Binder и может использовать его для прямого доступа к общедоступным методам, доступным в реализации Binder или Service.

Этот способ предпочтителен, если сервис является фоновым рабочим процессом для вашего приложения. Единственный случай, когда этот способ создания интерфейса не является предпочтительным, – это когда ваш сервис используется другими приложениями или в рамках отдельных процессов.

Используйте мессенджер
Если вам нужно, чтобы интерфейс работал в разных процессах, вы можете создать интерфейс для сервиса с помощью Messenger. Таким образом, сервис определяет Handler, который отвечает на разные типы объектов Message.

Этот Handler служит основой для Messenger, который затем может передать IBinder клиенту, позволяя ему отправлять команды сервису с помощью объектов Message. Кроме того, клиент может определить собственный Messenger, чтобы сервис мог отправлять сообщения обратно.

Это самый простой способ межпроцессного взаимодействия (IPC), поскольку Messenger ставит все запросы в очередь в одном потоке, поэтому вам не нужно разрабатывать сервис с учетом потокобезопасности.

Используйте AIDL
Язык описания интерфейсов Android (AIDL) разбивает объекты на примитивы, которые может распознать операционная система, и упорядочивает их по процессам для выполнения IPC. Предыдущий метод, использующий Messenger, на самом деле основан на AIDL как базовой структуре.

Как упоминалось в предыдущем разделе, Messenger создает очередь из всех клиентских запросов в одном потоке, поэтому сервис получает запросы по одному. Однако если вы хотите, чтобы ваш сервис обрабатывал несколько запросов одновременно, вы можете использовать AIDL напрямую. В этом случае ваш сервис должен быть потокобезопасным и поддерживать многопоточность.

Чтобы использовать AIDL напрямую, создайте файл .aidl, определяющий программный интерфейс. Инструменты Android SDK используют этот файл для создания абстрактного класса, который реализует интерфейс и обрабатывает IPC. Затем вы можете расширить этот класс в своем сервисе.

Примечание. Для большинства приложений AIDL – не лучший выбор для создания привязанной службы, поскольку может потребоваться поддержка многопоточности, что усложнит реализацию. Поэтому в этом документе не рассматривается, как использовать его для вашего сервиса. Если вы уверены, что вам нужно использовать AIDL напрямую, ознакомьтесь с документацией по AIDL.

Расширение класса Binder

Если сервис используется только локальным приложением и не должен работать в разных процессах, вы можете реализовать собственный класс Binder, который предоставляет клиенту прямой доступ к открытым методам сервиса.

Примечание. Это работает, только если клиент и сервис находятся в одном приложении и процессе, что бывает чаще всего. Например, это хорошо подходит для музыкального приложения, которому необходимо привязать операцию к собственной службе, воспроизводящей музыку в фоновом режиме.

Вот как это сделать:

  1. В сервисе создайте экземпляр Binder, который выполняет одно из следующих действий:
    • Содержит общедоступные методы, которые может вызывать клиент.
    • Возвращает текущий экземпляр Service, у которого есть общедоступные методы, вызываемые клиентом.
    • Возвращает экземпляр другого класса, размещенного в сервисе, с общедоступными методами, которые может вызывать клиент.
  2. Верните этот экземпляр Binder из метода обратного вызова onBind().
  3. В клиенте получите 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 предоставляет метод getService(), с помощью которого клиенты могут получить текущий экземпляр LocalService. Это позволяет клиентам вызывать общедоступные методы в сервисе. Например, клиенты могут звонить в компанию "getRandomNumber()" через сервис.

Ниже приведен пример действия, которое привязывается к LocalService и вызывает getRandomNumber() при нажатии кнопки.

Kotlin

class BindingActivity : Activity() {
    private var mService: LocalService? = null
    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) {
            mService = null
            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)
        // Release the reference so the service can be garbage-collected once it's
        // destroyed. onServiceDisconnected() isn't called when the client unbinds.
        mService = null
        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 ?: return
            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);
        // Release the reference so the service can be garbage-collected once it's
        // destroyed. onServiceDisconnected() isn't called when the client unbinds.
        mService = null;
        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) {
            mService = null;
            mBound = false;
        }
    };
}

В примере выше показано, как клиент привязывается к сервису с помощью реализации ServiceConnection и обратного вызова onServiceConnected(). В следующем разделе приведена дополнительная информация о процессе привязки к сервису.

Примечание. В предыдущем примере метод onStop() отменяет привязку клиента к сервису и удаляет ссылку клиента на него. Отключайте клиентов от сервисов в подходящее время, как описано в разделе Дополнительные примечания.

Дополнительные примеры кода можно найти в классах LocalService.java и LocalServiceActivities.java в ApiDemos.

Используйте мессенджер

Если вам нужно, чтобы сервис взаимодействовал с удаленными процессами, вы можете использовать Messenger, чтобы предоставить интерфейс для сервиса. Этот метод позволяет выполнять межпроцессное взаимодействие (IPC) без использования AIDL.

Использовать Messenger для интерфейса проще, чем AIDL, потому что Messenger ставит в очередь все вызовы сервиса. Чистый интерфейс AIDL отправляет одновременные запросы к сервису, который затем должен обрабатывать многопоточность.

Для большинства приложений сервису не нужно выполнять многопоточность, поэтому использование Messenger позволяет сервису обрабатывать по одному вызову за раз. Если вам нужен многопоточный сервис, используйте для определения интерфейса AIDL.

Вот как использовать Messenger:

  1. Сервис реализует Handler, который получает обратный вызов для каждого вызова от клиента.
  2. Сервис использует Handler для создания объекта Messenger (который является ссылкой на Handler).
  3. Messenger создает IBinder, который сервис возвращает клиентам из onBind().
  4. Клиенты используют IBinder для создания экземпляра Messenger (который ссылается на Handler сервиса), используемого клиентом для отправки объектов Message в сервис.
  5. Сервис получает каждый Message в своем Handler, а именно в методе handleMessage().

Таким образом, у клиента нет методов для вызова сервиса. Вместо этого клиент доставляет сообщения (объекты Message), которые сервис получает в своем методе Handler.

Вот пример сервиса, использующего интерфейс 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();
    }
}

Метод handleMessage() в Handler – это место, где сервис получает входящий Message и решает, что делать, на основе элемента what.

Клиенту нужно лишь создать Messenger на основе IBinder, возвращенного сервисом, и отправить сообщение с помощью 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)
            mService = null
            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);
            mService = null;
            bound = false;
        }
    }
}

В этом примере не показано, как сервис может ответить клиенту. Если вы хотите, чтобы сервис отвечал, вам также нужно создать Messenger в клиенте. Когда клиент получает обратный вызов onServiceConnected(), он отправляет в сервис запрос Message, который включает Messenger клиента в параметре replyTo метода send().

Пример реализации двустороннего обмена сообщениями можно найти в примерах MessengerService.java (сервис) и MessengerServiceActivities.java (клиент).

Подключение к сервису

Компоненты приложения (клиенты) могут привязываться к сервису, вызывая метод bindService(). Затем система Android вызывает метод onBind() сервиса, который возвращает объект IBinder для взаимодействия с сервисом.

Привязка выполняется асинхронно, и bindService() возвращается немедленно, не возвращая IBinder клиенту. Чтобы получить IBinder, клиент должен создать экземпляр ServiceConnection и передать его в bindService(). ServiceConnection включает метод обратного вызова, который система использует для доставки IBinder.

Примечание. К сервису могут подключаться только действия, сервисы и поставщики контента. Подключиться к сервису из широковещательного приемника нельзя.

Чтобы привязать сервис к клиенту, выполните следующие действия:

  1. Реализуйте ServiceConnection.

    Вам нужно переопределить два метода обратного вызова:

    onServiceConnected()
    Система вызывает этот метод, чтобы передать объект IBinder, возвращенный методом onBind() сервиса.
    onServiceDisconnected()
    Система Android вызывает этот метод, когда связь с сервисом неожиданно прерывается, например в случае сбоя или принудительного завершения работы сервиса. Этот метод не вызывается, когда клиент отменяет привязку.
  2. Вызовите bindService(), передав реализацию ServiceConnection.

    Примечание. Если метод возвращает значение false, у клиента нет действительного подключения к сервису. Однако в клиенте необходимо вызвать unbindService(). В противном случае клиент не позволит сервису завершить работу, когда он неактивен.

  3. Когда система вызывает метод обратного вызова onServiceConnected(), вы можете начать вызывать сервис, используя методы, определенные интерфейсом.
  4. Чтобы отключиться от сервиса, вызовите unbindService().

    Если клиент все ещё привязан к сервису, когда приложение уничтожает клиент, привязка отменяется. Рекомендуется отменять привязку клиента сразу после завершения взаимодействия с сервисом. Это позволит отключить неиспользуемый сервис. Дополнительную информацию о том, когда следует привязывать и отвязывать сервис, можно найти в разделе Дополнительные примечания.

В следующем примере клиент подключается к сервису, созданному ранее путем расширения класса Binder. Поэтому все, что нужно сделать, – это привести возвращенный объект IBinder к классу LocalBinder и запросить экземпляр LocalService:

Kotlin

var mService: LocalService? = null

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")
        mService = null
        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");
        mService = null;
        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() с неявным намерением.

  • Второй параметр – объект ServiceConnection.
  • Третий параметр – это флаг, указывающий на параметры привязки. Обычно это BIND_AUTO_CREATE, чтобы создать сервис, если он ещё не запущен. Другие возможные значения: BIND_DEBUG_UNBIND, BIND_NOT_FOREGROUND или 0 (нет).

Дополнительные сведения

Вот несколько важных примечаний о привязке к сервису:

  • Всегда перехватывайте исключения DeadObjectException, которые возникают при разрыве соединения. Это единственное исключение, которое выдают удаленные методы.
  • Объекты подсчитываются по ссылкам в разных процессах.
  • Обычно привязка и отмена привязки выполняются в соответствующие моменты жизненного цикла клиента, как описано в следующих примерах:
    • Если вам нужно взаимодействовать с сервисом, только когда действие видно, привяжите его во время onStart() и отвяжите во время onStop().
    • Если вы хотите, чтобы ваше действие получало ответы, даже когда оно остановлено в фоновом режиме, привяжите его во время onCreate() и отмените привязку во время onDestroy(). Помните, что в этом случае сервис должен использоваться на протяжении всего времени работы действия, даже в фоновом режиме. Если сервис выполняется в другом процессе, то вы увеличиваете нагрузку на этот процесс, и система с большей вероятностью его завершит.

    Примечание. Обычно привязка и отмена привязки не выполняются во время обратных вызовов onResume() и onPause(), поскольку эти вызовы происходят при каждом переходе жизненного цикла. Сведите к минимуму обработку, которая происходит при этих переходах.

    Кроме того, если несколько операций в приложении привязаны к одному сервису и между двумя из них происходит переход, сервис может быть уничтожен и создан заново, поскольку текущая операция отвязывается (во время паузы) до того, как привязывается следующая (во время возобновления). Переход между действиями и координация их жизненных циклов описаны в статье Жизненный цикл объекта activity.

Дополнительные примеры кода, показывающие, как выполнить привязку к сервису, можно найти в классе RemoteService.java в ApiDemos.

Управление жизненным циклом привязанной службы

Когда служба отвязана от всех клиентов, система Android уничтожает ее (если она не была запущена с помощью startService()). Таким образом, вам не нужно управлять жизненным циклом службы, если она является исключительно привязанной. Система Android управляет им за вас в зависимости от того, привязан ли он к каким-либо клиентам.

Однако если вы решите реализовать метод обратного вызова onStartCommand(), то вам нужно будет явно остановить сервис, поскольку теперь он считается запущенным. В этом случае сервис работает до тех пор, пока не остановится сам с помощью метода stopSelf() или пока другой компонент не вызовет метод stopService(), независимо от того, привязан ли он к каким-либо клиентам.

Кроме того, если ваш сервис запущен и принимает привязку, то когда система вызывает метод onUnbind(), вы можете вернуть true, чтобы получить вызов onRebind() при следующей привязке клиента к сервису. onRebind() возвращает void, но клиент все равно получает IBinder в обратном вызове onServiceConnected(). На рисунке ниже показана логика такого жизненного цикла.

Жизненный цикл запущенной и привязанной службы: вызываются onStartCommand() и onBind(); когда все клиенты отвязываются, вызывается onUnbind(); при следующей привязке вызывается onRebind(), если onUnbind() возвращает true, в противном случае – onBind(); после остановки службы вызывается onDestroy().
Рисунок 1. Жизненный цикл службы, которая запущена и позволяет привязку.

Подробнее о жизненном цикле запущенного сервиса…