Когда следует использовать unbindService() и как правильно использовать ее для отвязки от удаленной службы, использующей интерфейс AIDL?

Я пишу простой музыкальный проигрыватель и создал службу воспроизведения, которая реализует интерфейс AIDL для связи с клиентами, один — простой браузер дорожек, а другой — еще более простую активность проигрывателя. Служба управляет объектом MediaPlayer, в то время как два действия используют ServiceConnections для получения соединений со службой.

Это включено в методы onStart() обоих действий:

@Override
public void onStart()
{
  super.onStart();
  Intent i = new Intent(this, PureService.class);
  startService(i);
  bindService(i, mConnection, 0);
}

Я сделал это для того, чтобы служба не останавливалась сразу при отвязке. Конечно, на самом деле это не было проблемой, потому что моя активность вообще отказывается отвязаться от службы. Каждый раз, когда мое приложение обращается к unbindService в любом из этих действий, unbindService каждый раз без исключения выдает исключение IllegalArgumentException (хе-хе).

В методах onStop:

@Override
public void onStop()
{
  super.onStop();

  if (mBound) {
    try {
      unbindService(mConnection);
    } catch (java.lang.IllegalArgumentException e)
    {
      //Print to log or make toast that it failed
    }
  }
  mBound = false;
}

Мне интересно вот что:

  • Должен ли я вызывать unbindService() в методе onStop()? Или вообще?
  • Я правильно называю?
  • Есть ли что-то особенное в том, как я запускаю/привязываю службу, о чем мне следует знать?
  • Я делаю что-то совершенно, совершенно неправильно? Я новичок в программировании для Android, так что это, конечно, не исключено.

Заранее спасибо.

РЕДАКТИРОВАТЬ: вот переопределения ServiceConnection

public void onServiceConnected(ComponentName className, IBinder service) {
  mBound = true;
  mService = IPureService.Stub.asInterface(service);
}
public void onServiceDisconnected(ComponentName arg0) {
  mBound = false;
}

В активности игрока есть дополнительный код, но он не связан с самой привязкой.


person Junseok Lee    schedule 11.07.2011    source источник


Ответы (3)


Во-первых, если вам действительно не нужно совершать вызовы этой службы между процессами (то есть из других .apks или вы используете android:process, чтобы по какой-то причине разделить свой собственный .apk на несколько процессов), тогда я действительно рекомендую просто отказ от использования помощи. Это больше сложности без выгоды. «Пример локальной службы» в документации службы показывает, как это сделать: http://developer.android.com/reference/android/app/Service.html

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

В реализации класса службы для воспроизведения музыки он будет использовать start, когда он активно выполняет воспроизведение (чтобы его процесс не был уничтожен системой, когда пользователь больше не взаимодействует с пользовательским интерфейсом приложения). Запуск службы, когда пользователь входит в пользовательский интерфейс, вероятно, вызовет затруднения, потому что теперь состояние запуска/остановки службы четко не определено — она может быть запущена либо из-за того, что она выполняет воспроизведение, либо из-за того, что пользователь зашел в пользовательский интерфейс приложения, и теперь, когда подходящее время, чтобы остановить его? Это будет хлопотно.

Теперь, что касается того, когда отвязывать - вам просто нужно убедиться, что вы всегда сопоставляете unbindService() с предыдущим bindService(). Из ваших фрагментов кода похоже, что вы делаете это, но в нем есть странные вещи, такие как mBound, который никогда не устанавливается. На самом деле, если вы последовательно выполняете привязку в onStart() и отвязываете в onStop(), вам никогда не понадобится mBound, чтобы решить, следует ли отменять привязку, потому что onStop() всегда вызывается после onStart().

Так что с кодом, который вы здесь приводите, не похоже, что есть проблема. Однако, если вы получаете исключения, очевидно, что они могут быть в другом месте вашего приложения. Чтобы сузить проблему, вы можете использовать этот флаг при вызове bindService() для получения дополнительной информации в журнале при возникновении сбоя: http://developer.android.com/reference/android/content/Context.html#BIND_DEBUG_UNBIND

person hackbod    schedule 11.07.2011
comment
На самом деле я потратил много времени, пытаясь заставить LocalBinder работать, но я очень хорошо помню, как имел дело с разочарованием, вызванным эквивалентом этой строки mBoundService = ((LocalService.LocalBinder)service).getService(); ... где я получал ClassCastException. Мне сказали, что использование AIDL решит проблему, и так оно и было, так что я согласился. Что касается вашего второго пункта, я пытался решить ранее, следует ли мне запускать воспроизведение с помощью намерения в onStartCommand, но вместо этого я решил использовать привязку. Может быть, я сделал неправильный выбор в тот момент? - person Junseok Lee; 11.07.2011
comment
Я понял, что не так. Я снова попытался использовать метод LocalBinder и обнаружил, что причина его неработоспособности заключалась в том, что я включил в AndroidManifest.xml, что служба должна запускаться в другом процессе. Я типа идиот. Спасибо за помощь. Это было высоко оценено. - person Junseok Lee; 11.07.2011

Несколько моментов:

  1. Возврат START_STICKY в onStartCommand, если вы хотите, чтобы ваш Сервис работал дольше. чем связанная деятельность.
  2. unbindService() в onStop в порядке: именно здесь я вызываю его в нескольких приложениях, и я никогда не видел этой конкретной ошибки. Я предполагаю, что у вас есть другая проблема с вашим ServiceConnection: покажите код для вашего объекта mConnection, и мы, вероятно, сможем выяснить, что с ним не так.
person Femi    schedule 11.07.2011
comment
Да, START_STICKY возвращается командой onStartCommand. Загружены переопределения mConnection - person Junseok Lee; 11.07.2011

У меня тоже была эта странная ошибка. Затем я попытался выполнить привязку к службе в onResume() вместо onStart() в Activity, и вуаля, больше никаких исключений! Я все еще немного не понимаю, почему это работает. Если бы кто-нибудь мог объяснить, я был бы одним счастливым кодером. :)

person Markus    schedule 14.03.2012