J'ai une situation particulière: Un service démarré par un récepteur de radiodiffusion commence une activité. Je veux permettre à cette activité de communiquer avec le service. J'ai choisi d'utiliser AIDL pour rendre cela possible. Tout semble fonctionner correctement sauf pour la méthode bindService()
appelée dans onCreate()
de l'activité. En fait, bindService () lève une exception de pointeur null car onServiceConnected()
n'est jamais appelé alors que la méthode onBind()
du service l'est. Quoi qu'il en soit, bindService()
renvoie true. Le service est évidemment actif car il démarre l'activité . Je sais qu'appeler une activité depuis un service peut sembler étrange, mais c'est malheureusement le seul moyen d'avoir la reconnaissance vocale dans un service.
Merci d'avance
Je ne peux pas inventer le problème exact à partir de votre description, je vais donc deviner ici!
Comment bindService()
peut-il lancer une NullPointerException
? La seule façon que cela pourrait (/ devrait) se produire est lorsque vous ne fournissez pas un auditeur Service
ou ServiceConnection
.
bindService()
ne peut pas lancer NullPointerException
car onServiceConnected()
n'est pas appelé. L'appel à onServiceConnected()
est un produit de bindService()
.
Donc, je suppose que vous appelez une méthode AIDL
, avant que la Service
ne soit réellement liée?
Je viens de faire l'expérience d'une autre version de ce problème, avec le même symptôme de onServiceConnected(...)
n'étant pas appelé. La cause était différente dans mon cas.
Vous devez vous assurer d’avoir une déclaration de service dans votre fichier AndroidManifest.xml dans la balise d’application - c’est la racine du problème pour moi.
<application Android:name=".YourAppTitle" Android:icon="@drawable/icon" Android:label="@string/app_name">
<activity Android:name=".Main" Android:label="@string/app_name">
</activity>
<service Android:name="YourService" />
</application>
Il existe une complication supplémentaire si vous utilisez une bibliothèque Android séparée dans Eclipse: l'ajout de cette étiquette de service ne semble résoudre le problème que si le service référencé se trouve dans le même package que le manifeste; Autrement dit, si votre application se trouve dans le package a.b.c et que réside ici le fichier AndroidManifest.xml, "YourService" doit également figurer dans le package a.b.c. (copiée manuellement depuis une autre bibliothèque, si nécessaire) ou bien la balise <service..>
peut/sera ignorée et onServiceConnected(...)
ne sera toujours pas appelé.
C'était le cas pour mon projet même si j'avais utilisé une instruction d'importation appropriée pour le Service dans mon code. Eclipse ne signalant aucune erreur, l'importation identifiait correctement la classe à partir d'une autre bibliothèque de l'espace de travail Eclipse.
HTH
Après des heures et des heures à essayer de comprendre cela, le problème est que les exemples illustrant la création du service n'incluent pas la méthode onBind ou qu'ils contiennent l'exemple de code suivant, ou qu'ils le génèrent pour vous:
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
La méthode onServiceConnected échouera ou ne sera jamais exécutée. Le correctif est très simple, ce qui suit:
public IBinder onBind(Intent intent) {
return mBinder;
}
Où vous pouvez créer un simple classeur tel que celui-ci à renvoyer:
private final IBinder mBinder = new LocalBinder();
public class LocalBinder extends Binder {
public ConferenceService getService() {
return ConferenceService.this;
}
}
L'événement onServiceConnected n'a jamais été appelé dans mon application.
Le problème était que le nom de service défini dans mon manifeste d'application était le suivant:
<service Android:name="MyService" Android:enabled="true"></service>
Une fois que j'ai changé le nom complet de la classe, cela a fonctionné:
<service Android:name="com.example.MyService" Android:enabled="true"></service>
Update: Vous pouvez également utiliser un nom de classe relatif:
<service Android:name=".MyService" Android:enabled="true"></service>
Spécifiez le nom de la classe en utilisant son entier com.example.MyServiceClass au lieu de simplement MyServiceClass.
Une autre chose est que si vous appelez la méthode bindservice
à l'intérieur de la méthode oncreate
, la onserviceconnected
est appelée une fois la méthode oncreate
terminée.
Ainsi, toute référence aux fonctions d'interface avant la fin de la oncreate
(ou avant l'appel de onserviceconnected
) indique une exception de pointeur null.
Une autre cause à la question initiale pourrait être que le service ne fonctionne pas déjà et que vous transmettez 0 en tant qu'indicateur à bindService. Ainsi:
bindService(intent, serviceConnection, 0);
Quand ce que vous cherchez serait:
bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
Il peut y avoir une autre explication, une situation peu fréquente, mais j’ai réussi à y entrer et à perdre 2 heures pour la résoudre.
Donc, ce que j'ai fait, c'est que je voulais réutiliser le paquet à partir de l'intention reçue par la méthode onBind. Mais je suis allé pour la version paresseuse et a changé la classe de l'intention. Apparemment, onServiceConnected n’est pas appelé. Probablement parce que le système garde une référence à l'intention et l'utilise lors de l'appel de onServiceConnected.
En conclusion, ne changez pas l'intention que vous recevez dans onBind.
Vous devez attendre pour terminer la méthode onCreate (). Exemple: Définissez votre service d’achat en bas:
Button button_useservice=findViewById(R.id.button_useservice);
button_useservice.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
UsinService();
}
});
J'appelais bind avec une intention vide - getContext().bindService(new Intent(), mConnection, Context.BIND_AUTO_CREATE)
. Je dois préciser l'intention plus précisément pour indiquer le service auquel je souhaite me connecter. C'est évidemment une erreur de code, mais la sortie de Logcat n'était malheureusement pas assez claire.
Si quelqu'un cherche toujours la réponse après avoir essayé tous les autres, cela pourrait aider… onServiceConnected()
n'est pas appelée immédiatement après bindService(...)
. cela prend quelques secondes. Donc, si vous recevez une valeur de onServiceConnected()
et que vous devez l’utiliser ailleurs dans onCreate
ou onStart
, une exception NullPointerException sera levée à cause de la retard. Donc, si vous pouvez déplacer cette ligne de code qui a besoin de la valeur de onCreate
ou onStart
, dans onServiceConnected(){......}
, en dessous de la ligne de déclaration de la valeur dont vous avez besoin, cela pourrait fonctionner.