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

Связанная служба — это сервер в интерфейсе клиент-сервер. Он позволяет таким компонентам, как действия, привязываться к службе, отправлять запросы, получать ответы и выполнять межпроцессное взаимодействие (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 :

Котлин

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
    }
}

Ява

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() при нажатии кнопки:

Котлин

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()
        }
    }
}

Ява

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() отвязывает клиента от службы. Отвязывайте клиентов от служб в подходящее время, как описано в разделе «Дополнительные примечания» .

Дополнительные примеры кода см. в классах 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 :

Котлин

/** 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
    }
}

Ява

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 :

Котлин

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
        }
    }
}

Ява

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() , он отправляет в службу 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 :

Котлин

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
    }
}

Ява

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() , как показано в следующем примере:

Котлин

Intent(this, LocalService::class.java).also { intent ->
    bindService(intent, connection, Context.BIND_AUTO_CREATE)
}

Ява

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() вашего действия, поскольку эти обратные вызовы происходят при каждом переходе жизненного цикла. Сведите обработку, происходящую при этих переходах, к минимуму.

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

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

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

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

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

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

Рисунок 1. Жизненный цикл службы, которая запущена и допускает привязку.

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