143 votes

L'activité <Nom de l'application> a fait fuir la connexion de service <Nom de la connexion de service>@438030a8 qui était initialement liée ici.

Je travaille sur ma première application Android. J'ai trois activités dans mon application, et l'utilisateur passe d'une activité à l'autre assez fréquemment. J'ai également un service distant, qui gère une connexion telnet. Les applications doivent se lier à ce service afin d'envoyer/recevoir des messages telnet.

Editar Merci BDLS pour votre réponse informative. J'ai réécrit mon code à la lumière de vos précisions sur la différence entre l'utilisation de l'option bindService() comme une fonction autonome ou après startService() Maintenant, je n'obtiens le message d'erreur "fuite" que par intermittence, lorsque j'utilise le bouton "retour" pour passer d'une activité à l'autre.

Mon activité de connexion est la suivante onCreate() y onDestroy() :

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    /*
     * Initialize the ServiceConnection.  Note that this is the only place startService() is run.
     * It is also the only time bindService is run without dependency on connectStatus.
     */
    conn = new TelnetServiceConnection();
    //start the service which handles telnet
    Intent i = new Intent();
    i.setClassName( "com.wingedvictorydesign.LightfactoryRemote", "com.wingedvictorydesign.LightfactoryRemote.TelnetService" );
    startService(i);
    //bind to the service
    bindService(i, conn, 0);

    setContentView(R.layout.connect);
    setupConnectUI();

}//end OnCreate()

@Override
protected void onDestroy() {
    super.onDestroy();

    //unbind the service and null it out
    if (conn != null) {
        unbindService(conn);
        conn = null;
        }

    if(connectStatus == 0) {
        //stop the service
        Intent i = new Intent();
        i.setClassName( "com.wingedvictorydesign.LightfactoryRemote", "com.wingedvictorydesign.LightfactoryRemote.TelnetService" );
        stopService(i);
        Log.d("LightfactoryRemote", "Connect onDestroy() attempted to stop service");
        }

    Log.d("LightfactoryRemote", "Connect onDestroy()");
    }//end onDestroy()

Le service est donc démarré lorsque l'activité est lancée, et arrêté lorsque l'activité est détruite si aucune connexion telnet réussie n'a été établie ( connectStatus == 0 ). Les autres activités ne se lient au service que si une connexion réussie a été établie ( connectStatus == 1 enregistrées dans des préférences partagées). Voici leur onResume() y onDestroy() :

@Override
protected void onResume() {
    super.onResume();

    //retrieve the shared preferences file, and grab the connectionStatus out of it.
    SharedPreferences settings = getSharedPreferences(PREFS_NAME, MODE_WORLD_WRITEABLE);
    connectStatus = settings.getInt("connectStatus", 0);

    Log.d("LightfactoryRemote", "Focus onResume with " + connectStatus);

    //if a telnet connection is active, start the service and bind to it
    if (connectStatus == 1) {
        conn = new TelnetServiceConnection();
        Intent i = new Intent();
        i.setClassName("com.wingedvictorydesign.LightfactoryRemote", "com.wingedvictorydesign.LightfactoryRemote.TelnetService");
        bindService(i, conn, 0);
        //TODO write restore texview code
        }//end if
    }//end onResume

@Override
protected void onDestroy() {
    super.onDestroy();
    //unbind the service and null it out.
    if (conn != null) {
        Log.d("LightfactoryRemote", "Focus onDestroy() attempted to unbind service");
        unbindService(conn);
        conn = null;
        }
    Log.d("LightfactoryRemote", "Focus onDestroy()");
    }//end onDestroy()

Donc la liaison se fait dans onResume() afin qu'il prenne en compte l'état modifié de l'activité de connexion, et dans la section onDestroy() il est délié, si nécessaire.

Fin d'édition

Mais je reçois toujours le message d'erreur "Activity has leaked ServiceConnection @438030a8 that was originally bound here" par intermittence lorsque je change d'activité. Qu'est-ce que je fais de mal ?

Merci d'avance pour tous les conseils ou les indications !!!

Le message d'erreur complet suit (à partir du code révisé) :

01-02 22:04:26.642: DEBUG/LightfactoryRemote(2024): Focus onStop()
01-02 22:04:26.642: DEBUG/LightfactoryRemote(2024): Focus onDestroy() attempted to unbind service
01-02 22:04:26.642: DEBUG/LightfactoryRemote(2024): Focus onDestroy()
01-02 22:04:26.672: ERROR/ActivityThread(2024): Activity com.wingedvictorydesign.LightfactoryRemote.LightfactoryRemote has leaked ServiceConnection com.wingedvictorydesign.LightfactoryRemote.LightfactoryRemote$TelnetServiceConnection@439e51e8 that was originally bound here
01-02 22:04:26.672: ERROR/ActivityThread(2024): android.app.ServiceConnectionLeaked: Activity com.wingedvictorydesign.LightfactoryRemote.LightfactoryRemote has leaked ServiceConnection com.wingedvictorydesign.LightfactoryRemote.LightfactoryRemote$TelnetServiceConnection@439e51e8 that was originally bound here
01-02 22:04:26.672: ERROR/ActivityThread(2024):     at android.app.ActivityThread$PackageInfo$ServiceDispatcher.<init>(ActivityThread.java:927)
01-02 22:04:26.672: ERROR/ActivityThread(2024):     at android.app.ActivityThread$PackageInfo.getServiceDispatcher(ActivityThread.java:822)
01-02 22:04:26.672: ERROR/ActivityThread(2024):     at android.app.ApplicationContext.bindService(ApplicationContext.java:842)
01-02 22:04:26.672: ERROR/ActivityThread(2024):     at android.content.ContextWrapper.bindService(ContextWrapper.java:319)
01-02 22:04:26.672: ERROR/ActivityThread(2024):     at com.wingedvictorydesign.LightfactoryRemote.LightfactoryRemote.onResume(LightfactoryRemote.java:102)
01-02 22:04:26.672: ERROR/ActivityThread(2024):     at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1225)
01-02 22:04:26.672: ERROR/ActivityThread(2024):     at android.app.Activity.performResume(Activity.java:3559)
01-02 22:04:26.672: ERROR/ActivityThread(2024):     at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2838)
01-02 22:04:26.672: ERROR/ActivityThread(2024):     at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2866)
01-02 22:04:26.672: ERROR/ActivityThread(2024):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2420)
01-02 22:04:26.672: ERROR/ActivityThread(2024):     at android.app.ActivityThread.access$2100(ActivityThread.java:116)
01-02 22:04:26.672: ERROR/ActivityThread(2024):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1794)
01-02 22:04:26.672: ERROR/ActivityThread(2024):     at android.os.Handler.dispatchMessage(Handler.java:99)
01-02 22:04:26.672: ERROR/ActivityThread(2024):     at android.os.Looper.loop(Looper.java:123)
01-02 22:04:26.672: ERROR/ActivityThread(2024):     at android.app.ActivityThread.main(ActivityThread.java:4203)
01-02 22:04:26.672: ERROR/ActivityThread(2024):     at java.lang.reflect.Method.invokeNative(Native Method)
01-02 22:04:26.672: ERROR/ActivityThread(2024):     at java.lang.reflect.Method.invoke(Method.java:521)
01-02 22:04:26.672: ERROR/ActivityThread(2024):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:791)
01-02 22:04:26.672: ERROR/ActivityThread(2024):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:549)
01-02 22:04:26.672: ERROR/ActivityThread(2024):     at dalvik.system.NativeStart.main(Native Method)
01-02 22:04:26.692: WARN/ActivityManager(558): Unbind failed: could not find connection for android.os.BinderProxy@43c509a8

Modifier le 2e
Merci encore une fois bdls pour vos suggestions. J'ai fait comme vous l'avez suggéré et j'ai ajouté un onUnBind() au service. onUnBind() n'est en fait déclenché que lorsque tous les clients se déconnectent du service, mais lorsque j'ai appuyé sur le bouton d'accueil, il a été exécuté, puis le message d'erreur s'est affiché ! Cela n'a aucun sens pour moi, car tous les clients ont été déconnectés du service, alors comment l'unique détruit pourrait-il fuir une serviceConnection ? Vérifiez :

01-03 19:38:30.837: DEBUG/LightfactoryRemote(1118): Focus onPause()1
01-03 19:38:31.577: WARN/IInputConnectionWrapper(1118): showStatusIcon on inactive InputConnection
01-03 19:38:31.587: DEBUG/LightfactoryRemote(1118): Focus onStop()
01-03 19:38:31.600: DEBUG/LightfactoryRemote(1118): Focus onDestroy() attempted to unbind service
01-03 19:38:31.607: DEBUG/LightfactoryRemote(1118): Focus onDestroy()
01-03 19:38:31.677: DEBUG/LightfactoryRemote(1125): TelnetService onUnBind()
01-03 19:38:31.727: ERROR/ActivityThread(1118): Activity com.wingedvictorydesign.LightfactoryRemote.LightfactoryRemote has leaked ServiceConnection com.wingedvictorydesign.LightfactoryRemote.LightfactoryRemote$TelnetServiceConnection@435baeb0 that was originally bound here
01-03 19:38:31.727: ERROR/ActivityThread(1118): android.app.ServiceConnectionLeaked: Activity com.wingedvictorydesign.LightfactoryRemote.LightfactoryRemote has leaked ServiceConnection com.wingedvictorydesign.LightfactoryRemote.LightfactoryRemote$TelnetServiceConnection@435baeb0 that was originally bound here
01-03 19:38:31.727: ERROR/ActivityThread(1118):     at android.app.ActivityThread$PackageInfo$ServiceDispatcher.<init>(ActivityThread.java:886)
01-03 19:38:31.727: ERROR/ActivityThread(1118):     at android.app.ActivityThread$PackageInfo.getServiceDispatcher(ActivityThread.java:781)
01-03 19:38:31.727: ERROR/ActivityThread(1118):     at android.app.ApplicationContext.bindService(ApplicationContext.java:820)
01-03 19:38:31.727: ERROR/ActivityThread(1118):     at android.content.ContextWrapper.bindService(ContextWrapper.java:307)
01-03 19:38:31.727: ERROR/ActivityThread(1118):     at com.wingedvictorydesign.LightfactoryRemote.LightfactoryRemote.onResume(LightfactoryRemote.java:102)
01-03 19:38:31.727: ERROR/ActivityThread(1118):     at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1225)
01-03 19:38:31.727: ERROR/ActivityThread(1118):     at android.app.Activity.performResume(Activity.java:3530)
01-03 19:38:31.727: ERROR/ActivityThread(1118):     at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2619)
01-03 19:38:31.727: ERROR/ActivityThread(1118):     at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2647)
01-03 19:38:31.727: ERROR/ActivityThread(1118):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2287)
01-03 19:38:31.727: ERROR/ActivityThread(1118):     at android.app.ActivityThread.access$1800(ActivityThread.java:112)
01-03 19:38:31.727: ERROR/ActivityThread(1118):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1692)
01-03 19:38:31.727: ERROR/ActivityThread(1118):     at android.os.Handler.dispatchMessage(Handler.java:99)
01-03 19:38:31.727: ERROR/ActivityThread(1118):     at android.os.Looper.loop(Looper.java:123)
01-03 19:38:31.727: ERROR/ActivityThread(1118):     at android.app.ActivityThread.main(ActivityThread.java:3948)
01-03 19:38:31.727: ERROR/ActivityThread(1118):     at java.lang.reflect.Method.invokeNative(Native Method)
01-03 19:38:31.727: ERROR/ActivityThread(1118):     at java.lang.reflect.Method.invoke(Method.java:521)
01-03 19:38:31.727: ERROR/ActivityThread(1118):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:782)
01-03 19:38:31.727: ERROR/ActivityThread(1118):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:540)
01-03 19:38:31.727: ERROR/ActivityThread(1118):     at dalvik.system.NativeStart.main(Native Method)
01-03 19:38:31.777: WARN/ActivityManager(564): Unbind failed: could not find connection for android.os.BinderProxy@4370f8a8

J'ai pensé qu'il pouvait s'agir de quelque chose comme vous l'avez dit, où la liaison avec le service n'est pas complète lorsque unbindService() est appelé, mais j'ai essayé d'appeler une méthode sur le service au fur et à mesure que j'avançais dans chaque activité pour vérifier que la liaison est complète, et elles sont toutes passées sans problème.

En général, ce comportement ne semble pas lié au temps que je passe dans chaque activité. Cependant, dès que la première activité laisse échapper sa serviceConnection, toutes les autres le font dès que j'y retourne.

Autre chose, si j'active l'option "Immédiatement détruire les activités" dans Dev Tools, cela évite cette erreur.

Des idées ?

58voto

bdls Points 1887

Vous n'avez fourni aucun de vos codes de LightFactoryRemote Il ne s'agit donc que d'une présomption, mais il semble que ce soit le genre de problème que vous rencontreriez si vous utilisiez la méthode d'évaluation de l'impact sur l'environnement. bindService en tant que telle.

Pour s'assurer qu'un service continue à fonctionner, même après que l'activité qui l'a démarré a eu son temps de réponse, il faut que le service soit mis à jour. onDestroy appelée, vous devez d'abord utiliser la méthode startService .

La documentation Android pour startService l'État :

L'utilisation de startService() annule la durée de vie par défaut du service qui est gérée par bindService(Intent, ServiceConnection, int) : elle exige que le service reste en cours d'exécution jusqu'à ce que stopService(Intent) soit appelé, que des clients soient connectés ou non.

Considérant que pour bindService :

Le service sera considéré comme requis par le système uniquement tant que le contexte d'appel existe. Par exemple, si ce contexte est une activité qui est arrêtée, le service ne sera pas requis pour continuer à fonctionner jusqu'à ce que l'activité soit reprise.


Ce qui s'est passé, c'est que l'activité qui liait (et donc démarrait) le service a été arrêtée. Le système pense donc que le service n'est plus nécessaire et provoque cette erreur (puis arrête probablement le service).


Exemple

Dans cet exemple, le service doit être maintenu en fonctionnement, que l'activité appelante soit en cours ou non.

ComponentName myService = startService(new Intent(this, myClass.class));
bindService(new Intent(this, myClass.class), myServiceConn, BIND_AUTO_CREATE);

La première ligne démarre le service, et la seconde le lie à l'activité.

50voto

Mostafa Rostami Points 121

Vous pouvez utiliser :

@Override
public void onDestroy() {
    super.onDestroy();

    if (mServiceConn != null) {
        unbindService(mServiceConn);
    }
}

13voto

pierr Points 9148

Vous ne devriez avoir besoin de délier le service qu'en onDestroy() . Ensuite, l'avertissement disparaîtra.

Voir aquí .

Comme le document Activity tente de l'expliquer, il y a trois principaux groupes de liaison/déliaison que vous utiliserez : onCreate() et onDestroy(), onStart() et onStop(), et onResume() et onPause().

11voto

bdls Points 1887

Vous mentionnez que l'utilisateur passe d'une activité à l'autre assez rapidement. Se pourrait-il que vous appeliez unbindService avant que le branchement ne soit établi ? Cela peut avoir pour effet d'échouer à délier, puis de faire fuir la liaison.

Je ne sais pas vraiment comment vous pourriez gérer ça... Peut-être que lorsque onServiceConnected est appelé, vous pourriez appeler unbindService si onDestroy a déjà été appelé. Je ne sais pas si ça va marcher.


Si vous ne l'avez pas encore fait, vous pouvez ajouter une méthode onUnbind à votre service. De cette façon, vous pouvez voir exactement quand vos classes se détachent du service, et cela peut aider au débogage.

@Override
public boolean onUnbind(Intent intent) {
    Log.d(this.getClass().getName(), "UNBIND");
    return true;
}

2voto

Ashwini Points 1781

Essayez d'utiliser unbindService() dans OnUserLeaveHint(). Cela empêche le scénario ServiceConnection leaked et d'autres exceptions.
Je l'ai utilisé dans mon code et cela fonctionne bien.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X