L'attività <Nome app> ha trapelato ServiceConnection <Nome serviceConnection> @ 438030a8 che era originariamente associato qui


134

Sto lavorando alla mia prima app per Android. Ho tre attività nella mia app e l'utente passa avanti e indietro abbastanza frequentemente. Ho anche un servizio remoto, che gestisce una connessione telnet. Le app devono associarsi a questo servizio per poter inviare / ricevere messaggi telnet.

Modifica Grazie BDLS per la risposta informativa. Ho riscritto il mio codice alla luce del vostro chiarimento sulla differenza tra l'utilizzobindService()come funzione autonoma o successivastartService(), e ora ricevo il messaggio di errore di perdita solo in modo intermittente quando si utilizza il pulsante Indietro per scorrere tra le attività.

La mia attività di connessione ha i seguenti onCreate()e 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()

Pertanto, il servizio viene avviato all'avvio dell'attività e interrotto quando l'attività viene distrutta se non viene stabilita alcuna connessione Telnet ( connectStatus == 0). Le altre attività si legano al servizio solo se è stata stabilita una connessione corretta ( connectStatus == 1, salvata in preferenze condivise). Ecco il loro onResume()e 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()

Quindi l'associazione si verifica in onResume()modo che rileverà lo stato modificato dall'attività di connessione e nella onDestroy()funzione non è associata, se necessario.

Fine modifica

Ma ricevo ancora il messaggio di errore di perdita di memoria "L'attività ha fatto trapelare ServiceConnection @ 438030a8 che era originariamente associato qui" in modo intermittente quando si cambia attività. Che cosa sto facendo di sbagliato?

Grazie in anticipo per eventuali suggerimenti o suggerimenti !!!

Segue il messaggio di errore completo (dal codice rivisto):

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

Modifica il 2 °
Grazie ancora bdls per i tuoi suggerimenti. Ho fatto come mi hai suggerito e aggiunto unaonUnBind()sostituzione al servizio. onUnBind()viene effettivamente attivato solo quando tutti i client si disconnettono dal servizio, ma quando premo il pulsante home, viene eseguito, quindi viene visualizzato il messaggio di errore! Questo non ha senso per me, dal momento che tutti i clienti sono stati slegati dal servizio, quindi come può uno distrutto perdere un servizioConnessione? Controlla:

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

Ho pensato che potesse essere qualcosa come hai detto, in cui l'associazione al servizio non è completa quando unbindService()viene chiamata, tuttavia ho provato a chiamare un metodo sul servizio mentre eseguivo il backup di ogni attività per verificare che l'associazione sia completa e sono andati tutti attraverso bene.

In generale, questo comportamento non sembra correlato alla durata di ciascuna attività. Una volta che la prima attività perde il suo serviceConnection, tuttavia, fanno tutti come faccio dopo.

Un'altra cosa, se attivo "Distruggi immediatamente le attività" in Dev Tools, impedisce questo errore.

Qualche idea?


Puoi aggiungere il codice LightfactoryRemote.onCreate ()? (com.wingedvictorydesign.LightfactoryRemote.LightfactoryRemote.onCreate (LightfactoryRemote.java:97))
tbruyelle

Risposte:


57

Non hai fornito alcun codice dal tuo LightFactoryRemote, quindi questa è solo una presunzione, ma sembra il tipo di problema che potresti vedere se stessi usando il bindServicemetodo da solo.

Per garantire che un servizio sia mantenuto in esecuzione, anche dopo che l'attività che è stata avviata ha avuto il suo onDestroymetodo chiamato, è necessario innanzitutto utilizzare startService.

I documenti Android per lo stato di startService :

L'uso di startService () ignora la durata del servizio predefinita gestita da bindService (Intent, ServiceConnection, int): richiede che il servizio rimanga in esecuzione fino a quando viene chiamato stopService (Intent), indipendentemente dal fatto che vi siano client collegati.

Considerando che per bindService :

Il servizio sarà considerato richiesto dal sistema solo finché esiste il contesto chiamante. Ad esempio, se questo contesto è un'attività che viene interrotta, il servizio non sarà richiesto per continuare l'esecuzione fino a quando l'attività non viene ripresa.


Quindi ciò che è accaduto è l'attività che ha associato (e quindi avviato) il servizio, è stato arrestato e quindi il sistema pensa che il servizio non sia più necessario e causa tale errore (e quindi probabilmente interrompe il servizio).


Esempio

In questo esempio il servizio deve essere mantenuto in esecuzione indipendentemente dal fatto che l'attività di chiamata sia in esecuzione.

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

La prima riga avvia il servizio e la seconda lo lega all'attività.


Inizio il servizio utilizzando START_STICKY ed è avviato anche dall'intento di avvio. Se chiamo StartService crea un'altra istanza del servizio e non voglio che 2 servizi vengano eseguiti contemporaneamente. Come posso correggere l'errore in questo caso?
opc0de,

16
@ opc0de, no non stai creando un altro servizio quando chiami due volte startService (). I servizi sono logicamente singleton per natura. Non importa quante volte lo avvii, viene eseguito solo un servizio.
Mahkie,

2
Qual è la soluzione per continuare il servizio in background per il lettore musicale?
Anand Savjani,

45

Puoi usare:

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

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

Eccellente. Questo è quello che è.
Seltsam,

31

Ti onResumeattacchi ma non ti sciogli onDestroy. Dovresti invece effettuare la non onPauseassociazione, in modo che ci siano sempre coppie corrispondenti di chiamate bind / unbind. I tuoi errori intermittenti saranno dove la tua attività viene messa in pausa ma non distrutta e quindi ripresa di nuovo.


13

Dovresti solo sbloccare il servizio onDestroy(). Quindi, verrà visualizzato l'avviso.

Vedere qui .

Come il documento Activity cerca di spiegare, ci sono tre raggruppamenti principali di bind / unbind che userete: onCreate () e onDestroy (), onStart () e onStop (), e onResume () e onPause ().


7
come avresti potuto sperimentare su Distruggi praticamente non viene mai chiamato dal sistema operativo
martyglaubitz

Vedi qui il link inoltra a contenuti vietati -> Avviso contenuti vietati. Qualcuno può ottenere l'accesso? Il pulsante "Continua al gruppo" aggiorna la pagina e mostra lo stesso avviso per me.
Blaze Gawlik,

11

Dici che l'utente passa rapidamente da un'attività all'altra. Potrebbe essere che stai chiamandounbindService prima che sia stata stabilita la connessione del servizio? Ciò potrebbe avere l'effetto di non sciogliersi, perdendo quindi il legame.

Non sono del tutto sicuro di come potresti gestirlo ... Forse quando onServiceConnectedviene chiamato potresti chiamare unbindServicese onDestroyè già stato chiamato. Non sono sicuro se funzionerà comunque.


Se non l'hai già fatto, puoi aggiungere un metodo onUnbind al tuo servizio. In questo modo puoi vedere esattamente quando le tue classi si separano da esso, e potrebbe aiutare con il debug.

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

2

Prova a utilizzare unbindService () in OnUserLeaveHint (). Impedisce lo scenario trapelato da ServiceConnection e altre eccezioni.
L'ho usato nel mio codice e funziona benissimo.


1

Puoi semplicemente controllarlo con un valore booleano, quindi puoi chiamare unbind solo se è stato effettuato il bind

public void doBindService()
{
    if (!mIsBound)
    {
        bindService(new Intent(this, DMusic.class), Scon, Context.BIND_AUTO_CREATE);
        mIsBound = true;
    }
}

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

Se vuoi scioglierlo solo se è stato collegato

public ServiceConnection Scon = new ServiceConnection() {

    public void onServiceConnected(ComponentName name, IBinder binder)
    {
        mServ = ((DMusic.ServiceBinder) binder).getService();
        mIsBound = true;
    }

    public void onServiceDisconnected(ComponentName name)
    {
        mServ = null;
    }
};

0

Ogni servizio associato ad attività deve essere privo di vincoli alla chiusura dell'app.

Quindi prova a usare

 onPause(){
   unbindService(YOUR_SERVICE);
   super.onPause();
 }

0

Ho letto di recente sul servizio Android e ho avuto la possibilità di approfondire. Ho incontrato una perdita di servizio, per la mia situazione è accaduto perché ho avuto un non legato servizio, che stava iniziando un limite di servizio, ma in questa mia non legato servizio è sostituito da un Activity .

Quindi, quando stavo interrompendo il mio servizio non associato utilizzando stopSelf () si è verificata la perdita, il motivo era che stavo interrompendo il servizio parent senza svincolare il servizio associato. Ora il servizio associato è in esecuzione e non sa a chi appartiene.

La soluzione semplice e diretta è che dovresti chiamare unbindService (YOUR_SERVICE); nel tuo onDestroy () funzione dell'attività / servizio principale. In questo modo il ciclo di vita garantirà l'arresto o la pulizia dei servizi associati prima che le attività / i servizi principali vengano interrotte.

C'è un'altra variante di questo problema. A volte nel tuo servizio associato vuoi che determinate funzioni funzionino solo se il servizio è associato, quindi finiamo per mettere un flag associato in onServiceConnected come:

public void onServiceConnected(ComponentName name, IBinder service) {
            bounded = true;
            // code here
        }

Funziona bene fino a qui, ma il problema si presenta quando trattiamo la funzione onServiceDisconnected come un callback per la chiamata della funzione unbindService , questo per documentazione viene chiamato solo quando un servizio viene interrotto o arrestato . E non avrai mai questo callback nello stesso thread . Quindi, finiamo per fare qualcosa del tipo:

public void onServiceDisconnected(ComponentName name) {
            bounded = false;
        }

Il che crea un grave bug nel codice perché il nostro flag associato non viene mai ripristinato su false e quando questo servizio viene ricollegato la maggior parte delle volte lo è true. Quindi, al fine di evitare questo scenario, dovresti impostare boundsu false nel momento in cui stai chiamandounbindService .

Questa è la copertina in modo più dettagliato nel blog di Erik .

Spero che chi sia mai venuto qui abbia soddisfatto la sua curiosità.


0

questo errore si verifica quando si intende associare un servizio limitato. quindi, sol dovrebbe essere: -

  1. nella connessione di servizio aggiungere serviceBound come di seguito:

    private final ServiceConnection serviceConnection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        // your work here.
    
        serviceBound = true;
    
    }
    
    @Override
    public void onServiceDisconnected(ComponentName name) {
    
        serviceBound = false;
    }

    };

  2. sbloccare il servizio su Distruggi

        if (serviceBound) {
            unbindService(serviceConnection);
        }
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.