Подтвердить что ты не робот

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 безопасно или проверить, привязан ли он к службе прежде, чем отменить его?

Спасибо заранее.

4b9b3361

Ответ 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(...);