Android: как безопасно отключить услугу
У меня есть служба, которая привязана к контексту приложения следующим образом:
getApplicationContext().bindService(
new Intent(this, ServiceUI.class),
serviceConnection,
Context.BIND_AUTO_CREATE
);
protected void onDestroy() {
super.onDestroy();
getApplicationContext().unbindService(serviceConnection);
}
По какой-то причине только иногда контекст приложения не привязывается должным образом (я не могу исправить эту часть), однако в onDestroy() я делаю unbindservice
, который выдает ошибку
java.lang.IllegalArgumentException: Service not registered: tools.cdevice.Devices$mainServiceConnection.
Мой вопрос: есть ли способ позвонить unbindservice
безопасно или проверить, привязан ли он к службе прежде, чем отменить его?
Спасибо заранее.
Ответы
Ответ 1
Попробуйте следующее:
boolean isBound = false;
...
isBound = getApplicationContext().bindService( new Intent(getApplicationContext(), ServiceUI.class), serviceConnection, Context.BIND_AUTO_CREATE );
...
if (isBound)
getApplicationContext().unbindService(serviceConnection);
Примечание:
Вы должны использовать тот же context
для привязки службы и открепления службы. Если вы связываете Сервис с getApplicationContext()
, поэтому вы также должны использовать getApplicationContext.unbindService(..)
Ответ 2
Здесь вы можете найти хорошее объяснение и исходники, как работать со связанными службами. В вашем случае вы должны переопределить методы (onServiceConnected
и onServiceDisconnected
) объекта ServiceConnection
. Затем вы можете просто проверить переменную mBound
в вашем коде.
Ответ 3
Выполнение того, что предложил Андрей Новиков, для меня не сработало.
Я просто заменил:
getApplicationContext().unbindService(serviceConnection);
С
unbindService(serviceConnection);
Ответ 4
Я обнаружил, что есть две проблемы. Попытка связываться не раз, а также пытаться развязать несколько раз.
Решение:
public class ServiceConnectionManager implements ServiceConnection {
private final Context context;
private final Class<? extends Service> service;
private boolean attemptingToBind = false;
private boolean bound = false;
public ServiceConnectionManager(Context context, Class<? extends Service> service) {
this.context = context;
this.service = service;
}
public void bindToService() {
if (!attemptingToBind) {
attemptingToBind = true;
context.bindService(new Intent(context, service), this, Context.BIND_AUTO_CREATE);
}
}
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
attemptingToBind = false;
bound = true;
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
bound = false;
}
public void unbindFromService() {
attemptingToBind = false;
if (bound) {
context.unbindService(this);
bound = false;
}
}
}
Ответ 5
Я думаю, что guide не совсем корректно, как упоминалось здесь Сурья Wijaya Madjid. Утечки памяти могут возникать, когда связанная служба уничтожается, а не повторно подключается.
Я думаю, что этот подход необходим:
Service mService;
private final ServiceConnection mServiceConnection = new ServiceConnection()
{
boolean bound = false;
@Override
public void onServiceDisconnected(ComponentName name)
{
mService = null;
}
@Override
public void onServiceConnected(ComponentName name, IBinder service)
{
mService = ((MyService.ServiceBinder) service).getService();
if (!bound)
{
// do some action - service is bound for the first time
bound = true;
}
}
};
@Override
public void onDestroy()
{
if (mService != null)
{
// do some finalization with mService
}
if (mServiceConnection.bound)
{
mServiceConnection.bound = false;
unbindService(mServiceConnection);
}
super.onDestroy();
}
public void someMethod()
{
if (mService != null)
{
// to test whether Service is available, I have to test mService, not mServiceConnection.bound
}
}
Ответ 6
Почему мы получаем эту ошибку?
При попытке отменить регистрацию службы, которая не зарегистрирована.
Каковы некоторые общие примеры?
- Связывание и открепление службы с другим контекстом.
- вызов
unBind(mserviceConnection)
больше, чем bind(...)
Первый момент говорит сам за себя. Давайте рассмотрим второй источник ошибок более глубоко. Отладьте ваши вызовы bind() и unbind(). Если вы видите вызовы в таком порядке, ваше приложение в итоге получит IllegalArgumentException
.
![enter image description here]()
Как мы можем избежать этого?
Есть два способа привязать и отменить привязку службы в Activity. Документы по Android рекомендуют
- Если вы хотите взаимодействовать со службой только тогда, когда видимость видна, тогда
bindService() в onStart()
и unbindService() в onStop()
Your Activity {
@Override
public void onStart(){
super.onStart();
bindService(intent, mConnection , Context.BIND_AUTO_CREATE);
}
@Override
public void onStop(){
super.onStop();
unbindService(mConnection);
}
}
- Если вы хотите взаимодействовать со службой, даже если активность находится в фоновом режиме, тогда
bindService() в onCreate()
и unbindService() в onDestroy()
Your Activity {
@Override
public void onCreate(Bindle sis){
super.onCreate(sis);
....
bindService(intent, mConnection , Context.BIND_AUTO_CREATE);
}
@Override
public void onDestroy() {
super.onDestroy();
unbindService(mConnection);
}
}
Ответ 7
Не уверен обо всех вышеперечисленных ответах, он казался слишком сложным, хотя ни один из них не соответствовал бы моей проблеме.
Только привязка/развязка один раз за раз, и служба была определенно связана во время вызова unbind(). Не хочу ничего утешать, поэтому я просто убедился, что использую тот же контекст для вызовов bind() и unbind(), которые решили его постоянно! Делать что-то вроде этого:
any_context.getApplicationContext().bind(...);
...
another_context.getApplicationContext().unbind(...);