Mc Flurry Posté(e) 5 mai 2011 Share Posté(e) 5 mai 2011 Solution : Il faut utiliser : getApplicationContext().bindService(...) au lieu de juste bindService(...) ! Bonjour, dans mon Activity principale, je crée un TabHost et 3 TabWidget. J'ai donc 4 Activity et 4 fichier XML. Un bouton est déclaré dans le fichier XML du premier TabWidget. J'ai besoin d'obtenir ce bouton pour lui ajouter un listener qui lance un service local et a donc qui a besoin du Context de l'Activity principale. Seulement il n'a pas été encore créer... findViewById() me retourne null ! Voici le code de mon Activity principale : package com.application.activity; import android.app.TabActivity; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.content.res.Resources; import android.os.Bundle; import android.os.IBinder; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.TabHost; import com.application.service.BackgroundService; import com.application.service.BackgroundServiceBinder; import com.application.service.IBackgroundService; import com.application.service.IBackgroundServiceListener; public class MainActivity extends TabActivity { private static final String TAG = "MainActivity "; /** Called when the activity is first created. */ public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); Resources res = getResources(); // Objet permettant de récupérer le // contenu de Drawable TabHost tabHost = getTabHost(); // L'activity TabHost TabHost.TabSpec spec; // Objet temporaire stockant un TabSpec Intent intent; // Objet temporaire permettant de paramétrer les activity // de chaque TabSpec // Initialisation de lobjet intent en precisant quelle acivity il // contient. intent = new Intent().setClass(this, HomeActivity.class); // Initialisation de l'onglet et ajout au TabHost spec = tabHost .newTabSpec("home") .setIndicator("Acceuil", res.getDrawable(R.drawable.ic_tab_home)) .setContent(intent); tabHost.addTab(spec); // Meme operation pour les onglets suivant intent = new Intent().setClass(this, DetailsActivity.class); spec = tabHost .newTabSpec("details") .setIndicator("Détails", res.getDrawable(R.drawable.ic_tab_details)) .setContent(intent); tabHost.addTab(spec); intent = new Intent().setClass(this, AboutActivity.class); spec = tabHost .newTabSpec("about") .setIndicator("A propos", res.getDrawable(R.drawable.ic_tab_about)) .setContent(intent); tabHost.addTab(spec); // Choix de l'onglet affiché lors du lancement de l'application tabHost.setCurrentTab(0); // Application d'un listener sur le bouton marche pour lancer la mise à jour automatique final Intent intentService = new Intent(this, BackgroundService.class); final IBackgroundServiceListener listener = new IBackgroundServiceListener() { public void dataChanged(final Object data) { MainActivity .this.runOnUiThread(new Runnable() { public void run() { Log.d(TAG, "Mise a jour des données"); } }); } }; final ServiceConnection connection = new ServiceConnection() { public void onServiceConnected(ComponentName name, IBinder binder) { Log.d("BackgroundService", "Connecté!"); IBackgroundService service = ((BackgroundServiceBinder) binder) .getService(); service.addListener(listener); } public void onServiceDisconnected(ComponentName name) { Log.i("BackgroundService", "Déconnecté!"); } }; Button marche = (Button) findViewById(R.id.marche); marche.setOnClickListener(new OnClickListener() { public void onClick(View v) { bindService(intentService, connection, Context.BIND_AUTO_CREATE); } }); } } Je vois deux solutions possibles à ce problème : soit réussir à récupérer le bouton dans l'activity principale, soit passer le Context de l'Activity principale dans l'Activity qui gère le bouton. Mais je n'arrive à n'en réaliser aucune ! Si vous avez la solution ou d'autres méthodes plus propres je suis preneur ! Aidez moi s'il vous plait! Lien vers le commentaire Partager sur d’autres sites More sharing options...
chpil Posté(e) 5 mai 2011 Share Posté(e) 5 mai 2011 La question est : pourquoi as-tu besoin du contexte de l'activité principale dans l'activité qui veut lancer le service local ? ne peux-tu pas utiliser le contexte de l'activité dans laquelle tu te trouves pour récupérer ton service local ? D'une manière générale, tu ne pourras pas de toute façon récupérer des éléments d'une Activity depuis une autre, ce serait contraire à la façon de fonctionner d'Android (gestion du cycle de vie des Activity par le système) Lien vers le commentaire Partager sur d’autres sites More sharing options...
Mc Flurry Posté(e) 5 mai 2011 Auteur Share Posté(e) 5 mai 2011 Merci de ta réponse, C'est vrai que ce n'est pas une obligation, je m'étais mis en tête que c'était la première Activity lancée qui devait faire ce genre de chose... J'ai donc déplacé le code dans l'Activity correspondante voila ce que ça donne : package com.application.activity; import android.app.Activity; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.IBinder; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import com.application.loading.LoaderTask; import com.application.service.BackgroundService; import com.application.service.BackgroundServiceBinder; import com.application.service.IBackgroundService; import com.application.service.IBackgroundServiceListener; public class HomeActivity extends Activity { private final static String TAG ="HomeActivity"; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.home_layout); // AsyncTask qui permet l'actualisation des données LoaderTask task = new LoaderTask(this); task.execute(); // Application d'un listener sur le bouton marche pour lancer la mise à jour automatique final Intent intentService = new Intent(this, BackgroundService.class); final IBackgroundServiceListener listener = new IBackgroundServiceListener() { public void dataChanged(final Object data) { HomeActivity.this.runOnUiThread(new Runnable() { public void run() { Log.d(TAG, "Mise a jour des données"); } }); } }; final ServiceConnection connection = new ServiceConnection() { public void onServiceConnected(ComponentName name, IBinder binder) { Log.d("BackgroundService", "Connected!"); IBackgroundService service = ((BackgroundServiceBinder) binder) .getService(); service.addListener(listener); } public void onServiceDisconnected(ComponentName name) { Log.i("BackgroundService", "Disconnected!"); } }; Button marche = (Button) findViewById(R.id.marche); marche.setOnClickListener(new OnClickListener() { public void onClick(View v) { bindService(intentService, connection, Context.BIND_AUTO_CREATE); } }); } } Mais lorsque je clique sur le bouton de mise en marche du service, le LogCat m'affiche : 05-05 12:37:37.448: WARN/ActivityManager(71): Binding with unknown activity: android.os.BinderProxy@450d6e58 Je ne sais pas l'interpréter... Lien vers le commentaire Partager sur d’autres sites More sharing options...
chpil Posté(e) 5 mai 2011 Share Posté(e) 5 mai 2011 Je ne sais pas l'interpréter... Moi non plus, ça ne me parle pas plus que ça ;) A tout hasard, as-tu bien déclaré ton service dans ton AndroidManifest.xml ? Autre remarque: dans le onDestroy de ton Activity, il faudrait que tu fasses l'opération inverse de ce que tu fais dans le onCreate : désenregistrer le listener de ton service, et unbinder ton service Lien vers le commentaire Partager sur d’autres sites More sharing options...
Mc Flurry Posté(e) 6 mai 2011 Auteur Share Posté(e) 6 mai 2011 Moi non plus, ça ne me parle pas plus que ça ;) Ca me rassure ! Sinon pour le onDestroy, oui je l'ai mis en place c'est vrai qu'il ne faut pas l'oublier ! J'ai aussi déclaré mon service dans mon manifeste mais est ce que c'est la bonne méthode... <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.application.activity" android:versionCode="1" android:versionName="1.0"> <uses-permission android:name="android.permission.VIBRATE" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-sdk android:minSdkVersion="4" /> <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name="MainActivity " android:label="@string/app_name" android:theme="@android:style/Theme.NoTitleBar"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".HomeActivity"></activity> <activity android:name=".DetailsActivity"></activity> <activity android:name=".AboutActivity"></activity> <service android:name="com.application.service.BackgroundService" /> </application> </manifest> Il y a des erreurs? Merci. Lien vers le commentaire Partager sur d’autres sites More sharing options...
chpil Posté(e) 6 mai 2011 Share Posté(e) 6 mai 2011 A première vue, pas d'erreurs, ni dans le XML, ni dans le code Si tu nous mets un extract de tes classes/interfaces BackgroundService/Listener/Binder, on aura peut être une meilleure idée Lien vers le commentaire Partager sur d’autres sites More sharing options...
Mc Flurry Posté(e) 6 mai 2011 Auteur Share Posté(e) 6 mai 2011 J'ai trouvé ! En plus c'est simple et évident, ... Il faut utiliser : getApplicationContext().bindService([...]) au lieu de juste bindService ! Je me disais bien qu'il y avait une histoire de context :) Une question chpil, tu m'as parlé de désenregisrter mon service, mais je n'arrive pas a atteindre mon objet service dans le bouton... Alors voila le morceau de code pour les boutons au cas ou ça serve à quelqu'un... Button button = (Button) findViewById(R.id.marche); button.setOnClickListener(new OnClickListener() { public void onClick(View v) { getApplicationContext().bindService(intentService, connection, Context.BIND_AUTO_CREATE); TextView maj = (TextView) HomeActivity.this.findViewById(R.id.maj); maj.setText("activée"); maj.setTextColor(HomeActivity.this.getResources().getColor(R.color.couleurPos)); } }); button = (Button) findViewById(R.id.arret); button.setOnClickListener(new OnClickListener() { public void onClick(View v) { getApplicationContext().unbindService(connection); TextView maj = (TextView) HomeActivity.this.findViewById(R.id.maj); maj.setText("désactivée"); maj.setTextColor(HomeActivity.this.getResources().getColor(R.color.couleurNeg)); } }); Lien vers le commentaire Partager sur d’autres sites More sharing options...
chpil Posté(e) 6 mai 2011 Share Posté(e) 6 mai 2011 Il faut utiliser : getApplicationContext().bindService([...]) au lieu de juste bindService ! Je ne me souviens pas à avoir eu besoin d'utiliser getApplicationContext(). Peut-être est-ce dû dans ton cas au fait que ton Activity est une Activity d'un onglet de TabActivity... Une question chpil, tu m'as parlé de désenregisrter mon service, mais je n'arrive pas a atteindre mon objet service dans le bouton... Comprend pas la question... Lien vers le commentaire Partager sur d’autres sites More sharing options...
Mc Flurry Posté(e) 6 mai 2011 Auteur Share Posté(e) 6 mai 2011 Je ne me souviens pas à avoir eu besoin d'utiliser getApplicationContext(). Peut-être est-ce dû dans ton cas au fait que ton Activity est une Activity d'un onglet de TabActivity... Oui c'est exactement ça, c'est du au fait de la structure du TabHost et de ses TabWidget. Je renommerai le sujet d'ailleurs. Ma question fait suite à ta remarque : Autre remarque: dans le onDestroy de ton Activity, il faudrait que tu fasses l'opération inverse de ce que tu fais dans le onCreate : désenregistrer le listener de ton service, et unbinder ton service Je n'arrive pas à le mettre en place, il faut que je désenregistre et unbind mon service dans le onClick de mon bouton arrêt ou dans une autre méthode? Lien vers le commentaire Partager sur d’autres sites More sharing options...
chpil Posté(e) 6 mai 2011 Share Posté(e) 6 mai 2011 Il faut que tu désenregistres dans le listener de ton bouton "arret" si tu veux explicitement proposer l'arrêt de ton service ET dans le onDestroy pour gérer le cas où le service n'a pas été arrêté explicitement (en faisant attention de ne pas désenregistrer/arreter le service deux fois) Lien vers le commentaire Partager sur d’autres sites More sharing options...
Mc Flurry Posté(e) 6 mai 2011 Auteur Share Posté(e) 6 mai 2011 D'accord, mais je n'arrive pas à exécuter la méthode removeListerner() Lorsque je créer ma connexion : final ServiceConnection connection = new ServiceConnection() { public void onServiceConnected(ComponentName name, IBinder binder) { Log.d("BackgroundService", "Connected!"); IBackgroundService service = ((BackgroundServiceBinder) binder) .getService(); service.addListener(listener); } public void onServiceDisconnected(ComponentName name) { Log.i("BackgroundService", "Disconnected!"); } }; j'ai accès au binder qui me donne accès à mon service, mais je n'y ai pu accès par la suite ce qui m'empêche d'appeler explicitement service.removeListener(). Si il y besoin du contenu de mes classes qui gère le service je peux les mettre à dispo. Lien vers le commentaire Partager sur d’autres sites More sharing options...
chpil Posté(e) 6 mai 2011 Share Posté(e) 6 mai 2011 Il faut que tu gardes une référence sur ton Service dans ton Activity, de façon à pouvoir la référencer par la suite. Accessoirement, cette référence peut te servir à tester si tu es connecté ou non au Service (en la remettant à null une fois déconnecté) pour gérer le cas dans le onDestroy Lien vers le commentaire Partager sur d’autres sites More sharing options...
Mc Flurry Posté(e) 6 mai 2011 Auteur Share Posté(e) 6 mai 2011 Ha mais oui ! Et bien voila, sujet résolu dans sa totalité, j'édite le sujet pour que ça rentre dans les règles et c'est fini. Merci beaucoup. Lien vers le commentaire Partager sur d’autres sites More sharing options...
Recommended Posts
Archivé
Ce sujet est désormais archivé et ne peut plus recevoir de nouvelles réponses.