web-dev-qa-db-fra.com

Android Java.lang.IllegalArgumentException: service non enregistré

J'ai une configuration qui ressemble à ceci:

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

Cependant, je vois toujours de temps en temps l'erreur dans le titre: Java.lang.IllegalArgumentException: Service not registered Est généré lorsque unbindService() est appelé. Suis-je en train de manquer quelque chose de stupide, ou y a-t-il encore quelque chose? Je dois noter qu'il peut exister plusieurs de ce même fragment.

Modifier

Étant donné que personne ne semble réellement lire le code, laissez-moi vous expliquer. unbindService() n'appelle pas Context.unbindService(ServiceConnection) sauf si le service est lié (mBound) et il n'avait pas été appelé auparavant avant le onServiceDisconnected(...) le rappel a été renvoyé d'un appel précédent possible à unbindService().

Dans cet esprit, y a-t-il des cas où Android déliera votre service pour vous de telle sorte que le service deviendrait non lié mais onServiceDisconnected ne serait pas appelé, me laissant ainsi dans un état périmé?

En outre, j'utilise mon contexte d'application pour effectuer la liaison initiale. Supposons quelque chose comme:

@Override
public void onCreate() {
    mApplication = getContext().getApplicationContext();
}
36
dcow

Je me rends compte que cette question a déjà été répondue. Mais je pense qu'il y a des raisons de comprendre pourquoi les gens font cette erreur.

Le problème est vraiment avec les documents de formation. http://developer.Android.com/reference/Android/app/Service.html montre une implémentation correcte tandis que https://developer.Android.com/guide/components/bound -services.html dans le 'ActivityMessenger' montre une implémentation Very [~ # ~] incorrecte [~ # ~] .

Dans l'exemple 'ActivityMessenger' onStop () pourrait potentiellement être appelé avant que le service ne soit réellement lié.

La raison de cette confusion est qu'ils utilisent le booléen de service lié pour signifier différentes choses dans différents exemples. (principalement, bindService () était-il appelé OR est le service réellement connecté)

Dans les exemples corrects où unbind () est effectué en fonction de la valeur du booléen lié, le booléen lié indique que le bindService () a été appelé . Puisqu'il est mis en file d'attente pour l'exécution du thread principal, unbindService () doit être appelé (donc mis en file d'attente pour être exécuté), quel que soit le moment (si jamais) onServiceConnected () se produit.

Dans d'autres exemples, comme celui de http://developer.Android.com/reference/Android/app/Service.html . La limite indique que les services sont réellement liés afin que vous puissiez les utiliser et ne pas obtenir une exception NullPointerException. Notez que dans cet exemple, l'appel à unbindService () est toujours effectué et le booléen lié ne détermine pas s'il faut dissocier ou non .

16
aaronvargas

Utilisez mIsBound dans doBindService() et doUnbindService() au lieu de dans l'instance 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;
    }
}

C'est ainsi que cela se fait dans http://developer.Android.com/reference/Android/app/Service.html

25
Jacob Phillips

Java.lang.IllegalArgumentException: Service not registered Signifie que vous n'étiez pas lié au service lorsque unbindService() a été appelée.

Donc dans votre cas, onSomeEvent() n'a jamais été appelée avant l'appel à unbindService() dans onPause()

8
pelotasplus

Une autre raison possible de cette exception pourrait être que unbindService est appelé par le mauvais Context. Étant donné que les services peuvent être liés non seulement par des activités, mais également par d'autres instances héritées de Context (à l'exception de BroadcastReceivers), même par d'autres services, assurez-vous que unbindService est appelé par le contexte qui a lié le Service et non par le Service lui-même lié. Cela donnerait directement l'exception ci-dessus "Service non enregistré".

3

Raison?

Si dans votre activité, unbindService () est appelé avant bindService (), vous obtiendrez ce IllegalArgumentException.

Comment l'éviter?
C'est simple. Vous n'auriez pas besoin d'un indicateur booléen si vous liez et dissociez le service dans cet ordre.

Solution 1:

Lier dans onStart() et dissocier dans onStop()

Your Activity {

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

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

 } 

Solution 2:
Lier dans onCreate() et dissocier dans 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);
    }         

 }

Lien pertinent:

Documentation officielle Android suggère que
Si vous devez interagir avec le service uniquement pendant que votre activité est visible , alors allez avec Solution1 .
Si vous voulez que votre activité reçoive des réponses même si elle est arrêtée en arrière-plan , alors allez avec Solution2 .

0
Rohit Singh

J'ai exactement le même problème avec ma demande. De temps en temps, je reçois IllegalArgumentException. Je suppose que le cas spécial est causé lorsque le service n'est pas lié et que le onPause est appelé avantonServiceDisconnected. J'essaierais donc Synchronized pour assurer une exécution correcte.

0
slott