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

Android java.lang.IllegalArgumentException: служба не зарегистрирована

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

class MyFragment implements SomeEventListener {

    Application mAppContext;    

    boolean mBound;
    boolean mDidCallUnbind;
    MyIBinder mBinder;
    ServiceConnection mConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mBound = true;
            mBinder = (MyIBinder) service;
            mBinder.getThings();...
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            mDidCallUnbind = false;
            mBound = false;
            mBinder = null;
        }
    };

    ...

    @Override
    public void onSomeEvent() {
        mAppContext.bindService(...);
    }

    void unbindService() {
        if (mBound && !mDidCallUnbind) {
            mDidCallUnbind = true;
            mAppContext.unbindService(mConnection);
        }
    }

    @Override
    public void onPause() {
        unbindService();
        super.onPause();
    }
}

Тем не менее время от времени я все еще вижу ошибку в заголовке: java.lang.IllegalArgumentException: Service not registered, генерируется при unbindService(). Я скучаю по чему-то глупому или происходит что-то еще? Должен отметить, что может существовать более одного этого фрагмента.

редактировать

Поскольку на самом деле никто не читает код, позвольте мне объяснить. unbindService() не вызывает Context.unbindService(ServiceConnection) если служба не привязана (mBound) и она не была ранее вызвана до того, onServiceDisconnected(...) обратный вызов onServiceDisconnected(...) был onServiceDisconnected(...) из возможного предыдущего вызова unbindService().

Имеется в виду, есть ли случаи, когда Android отменит для вас ваш сервис так, что сервис станет несвязанным, но onServiceDisconnected не будет вызываться, оставляя меня в безвыходном состоянии?

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

@Override
public void onCreate() {
    mApplication = getContext().getApplicationContext();
}
4b9b3361

Ответ 1

Я понимаю, что на этот вопрос уже был дан ответ. Но я думаю, что есть причина, чтобы понять, почему люди совершают эту ошибку.

Проблема действительно с учебными документами. http://developer.android.com/reference/android/app/Service.html показывает правильную реализацию, а https://developer.android.com/guide/components/bound-services.html в "ActivityMessenger" показывает Очень НЕПРАВИЛЬНАЯ реализация.

В примере "ActivityMessenger" onStop() может быть вызван до того, как служба будет фактически привязана.

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

В правильных примерах, где unbind() выполняется на основе значения связанного логического значения, связанное логическое значение указывает, что был вызван bindService(). Поскольку он ставится в очередь для выполнения основного потока, необходимо вызвать unbindService() (поэтому он будет поставлен в очередь для выполнения), независимо от того, когда (если вообще когда-либо) происходит onServiceConnected().

В других примерах, например, в http://developer.android.com/reference/android/app/Service.html. Предел указывает, что Сервисы действительно связаны, так что вы можете использовать его и не получать исключение NullPointerException. Обратите внимание, что в этом примере вызов unbindService() все еще выполняется, и связанный логический параметр не определяет, следует ли отменять привязку или нет.

Ответ 2

Используйте mIsBound внутри doBindService() и doUnbindService() вместо экземпляра ServiceConnection.

ServiceConnection mConnection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        mBinder = (MyIBinder) service;
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
        mBinder = null;
    }
}; 

...

public void doBindService() {
    bindService(new Intent(this, MyService.class),
        mConnection, Context.BIND_AUTO_CREATE);
    mIsBound = true;
}

public void doUnbindService() {
    if (mIsBound) {
        unbindService(mConnection);
        mIsBound = false;
    }
}

Вот как это делается в http://developer.android.com/reference/android/app/Service.html

Ответ 3

java.lang.IllegalArgumentException: Service not registered означает, что вы не были связаны с обслуживанием при вызове unbindService().

Итак, в вашем случае onSomeEvent() никогда не вызывался перед вызовом unbindService() в onPause()

Ответ 4

Другой возможной причиной этого исключения может быть то, что unbindService вызывается из-за неправильного Context. Поскольку сервисы могут быть связаны не только с деятельностью, но и с другими экземплярами, унаследованными Context (за исключением BroadcastReceivers), даже другими сервисами, убедитесь, что unbindService вызывается контекстом, который связал Service а не привязанным Сам Service. Это приведет непосредственно к вышеприведенному исключению "Сервис не зарегистрирован".

Ответ 5

Причина?

Если в вашей Деятельности unbindService() вызывается до bindService(), то вы получите это IllegalArgumentException.

Как этого избежать?
Это просто. Вам не понадобится логический флаг, если вы привязываете и отменяете привязку сервиса в этом порядке.

Решение 1:

Привязать в onStart() и onStop() в onStop()

Your Activity {

    @Override
    public void onStart()
    {
        super.onStart();
        bindService(intent, mConnection , Context.BIND_AUTO_CREATE);
    }

    @Override
    public void onStop()
    {
        super.onStop();
        unbindService(mConnection);
    }

 } 

Решение 2:
Привязать в onCreate() и onDestroy() в 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);
    }         

 }

Соответствующая ссылка:

Официальная документация Android предполагает, что
Если вам нужно взаимодействовать со службой только тогда, когда ваша активность видна, перейдите к Solution1.
Если вы хотите, чтобы ваша деятельность получала ответы, даже если она остановлена в фоновом режиме, перейдите к решению Solution2.

Ответ 6

У меня такая же проблема с моим приложением. Время от времени я получаю IllegalArgumentException. Я предполагаю, что специальный случай возникает, когда служба несвязана, а onPause вызывается до onServiceDisconnected. Поэтому я бы попробовал Synchronized вещи для обеспечения правильного выполнения.

Ответ 7

class ServiceBindManager<T>(val context: Context, clazz: Class<T>) {

    val TAG: String = "ServiceBindManager"

    private val isBound: AtomicBoolean = AtomicBoolean(false)

    private var intent: Intent = Intent(context, clazz)

    private val connection: ServiceConnection = object : ServiceConnection {
        override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
            Log.d(TAG, "onServiceConnected: $context")
            isBound.set(true)
        }

        override fun onServiceDisconnected(name: ComponentName?) {
            Log.d(TAG, "onServiceDisconnected: $context")
            isBound.set(false)
        }

        override fun onBindingDied(name: ComponentName?) {
            isBound.set(false)
        }

        override fun onNullBinding(name: ComponentName?) {
            isBound.set(false)
        }
    }


     fun bindService() {
        Log.e(TAG, "bindService: $context")
        isBound.set(context.bindService(intent, connection, BIND_AUTO_CREATE))
    }

     fun unbindService() {
        Log.e(TAG, "unbindService: $context")
        if (isBound.get()) {
            isBound.set(false)
            context.unbindService(connection)
        }
    }

}

Использование:


override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        serviceBindManager = ServiceBindManager([email protected], MyService::class.java)
}

 override fun onStart() {
        super.onStart()
        serviceBindManager.bindService()
}

 override fun onStop() {
        super.onStop()
        serviceBindManager.unbindService()
}