A atividade <Nome do Aplicativo> vazou ServiceConnection <ServiceConnection Name> @ 438030a8 que foi originalmente vinculado aqui

134

Estou trabalhando no meu primeiro aplicativo para Android. Eu tenho três atividades no meu aplicativo e o usuário alterna com bastante frequência. Eu também tenho um serviço remoto, que lida com uma conexão telnet. Os aplicativos precisam se vincular a esse serviço para enviar / receber mensagens de telnet.

Editar Obrigado BDLS pela sua resposta informativa. Reescrevi meu código à luz do seu esclarecimento sobre a diferença entre usarbindService()como uma função autônoma ou posteriorstartService(), e agora só recebo a mensagem de erro de vazamento intermitentemente ao usar o botão Voltar para alternar entre as atividades.

Minha atividade de conexão tem o seguinte 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()

Portanto, o serviço é iniciado quando a atividade é iniciada e interrompido quando a atividade é destruída se nenhuma conexão telnet bem-sucedida foi estabelecida ( connectStatus == 0). As outras atividades se vinculam ao serviço apenas se uma conexão bem-sucedida foi estabelecida ( connectStatus == 1, salva em preferências compartilhadas). Aqui está o seu 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()

Portanto, a ligação ocorre onResume()para que ele retire o estado alterado da atividade de conexão e, na onDestroy()função, não seja vinculado, se necessário.

End Edit

Mas ainda recebo a mensagem de erro de vazamento de memória "A atividade vazou ServiceConnection @ 438030a8 que foi originalmente vinculada aqui" intermitentemente ao alternar atividades. O que estou fazendo de errado?

Agradecemos antecipadamente por todas as dicas ou sugestões !!!

A seguir, uma mensagem de erro completa (do código revisado):

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

Edite o segundo
Obrigado mais uma vez bdls por suas sugestões. Fiz o que você sugeriu e adicionou umaonUnBind()substituição ao serviço. onUnBind()na verdade, é acionado apenas quando todos os clientes se desconectam do serviço, mas quando eu clico no botão home, ele é executado, a mensagem de erro é exibida! Isso não faz sentido para mim, como todos os clientes foram desvinculados do serviço, então como o destruído vazou um serviceConnection? Confira:

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

Eu pensei que poderia ser algo como você disse, onde a ligação ao serviço não está completa quando unbindService()é chamada, no entanto, tentei chamar um método no serviço enquanto fazia o backup de cada atividade para verificar se a ligação estava completa e todos eles foram. através de multa.

Em geral, esse comportamento não parece relacionado ao tempo que permaneço em cada atividade. No entanto, uma vez que a primeira atividade vaza seu serviceConnection, todos eles fazem o que eu faço depois deles.

Outra coisa, se eu ativar "Destruir atividades imediatamente" no Dev Tools, isso evita esse erro.

Alguma ideia?

catdotgif
fonte
Você pode adicionar o código LightfactoryRemote.onCreate ()? (com.wingedvictorydesign.LightfactoryRemote.LightfactoryRemote.onCreate (LightfactoryRemote.java:97))
tbruyelle

Respostas:

57

Você não forneceu nenhum código LightFactoryRemote, portanto isso é apenas uma suposição, mas parece o tipo de problema que você estaria vendo se estivesse usando o bindServicemétodo por si próprio.

Para garantir que um serviço seja mantido em execução, mesmo após a atividade iniciada ter seu onDestroymétodo chamado, você deve primeiro usar startService.

Os documentos do Android para o estado startService :

O uso de startService () substitui a vida útil padrão do serviço gerenciada por bindService (Intent, ServiceConnection, int): requer que o serviço permaneça em execução até que stopService (Intent) seja chamado, independentemente de algum cliente estar conectado a ele.

Considerando que para bindService :

O serviço será considerado requerido pelo sistema apenas enquanto existir o contexto de chamada. Por exemplo, se este Contexto for uma Atividade parada, o serviço não precisará continuar em execução até que a Atividade seja retomada.


Então, o que aconteceu foi a atividade que vinculou (e, portanto, iniciou) o serviço, foi interrompida e, portanto, o sistema acha que o serviço não é mais necessário e causa esse erro (e provavelmente interrompe o serviço).


Exemplo

Neste exemplo, o serviço deve ser mantido em execução, independentemente de a atividade de chamada estar em execução.

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

A primeira linha inicia o serviço e a segunda o vincula à atividade.

bdls
fonte
Inicio o serviço usando START_STICKY e ele também é iniciado pela intenção de inicialização. Se eu ligar para o StartService, ele cria outra instância do serviço e não quero dois serviços em execução ao mesmo tempo. Como posso corrigir o erro neste caso?
Opc0de 10/10/12
16
@ opc0de, não, você não está criando outro serviço ao chamar startService () duas vezes. Os serviços são logicamente singletons por natureza. Não importa quantas vezes você o inicie, apenas um serviço é executado.
Mahkie
2
Qual é a solução para continuar o serviço em segundo plano para o music player?
Anand Savjani
45

Você pode usar:

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

    if (mServiceConn != null) {
        unbindService(mServiceConn);
    }
}
Mostafa Rostami
fonte
Excelente. É isso que é.
Seltsam 5/04
31

Você liga onResumemas desata onDestroy. Em onPausevez disso, você deve desdobrar , para que sempre haja pares correspondentes de chamadas de vinculação / desativação. Seus erros intermitentes serão onde sua atividade será pausada, mas não destruída, e depois retomada novamente.

usuario
fonte
13

Você só precisa desvincular o serviço onDestroy(). Então, o aviso irá.

Veja aqui .

Como o documento Activity tenta explicar, existem três grupos principais de bind / unbind que você usará: onCreate () e onDestroy (), onStart () e onStop () e onResume () e onPause ().

pierrotlefou
fonte
7
como você deve ter eyperienced onDestroy praticamente é não chamado a partir do sistema operacional
martyglaubitz
Consulte aqui o link para o conteúdo banido -> Aviso de conteúdo banido. Alguém pode obter acesso? O botão "Continuar no grupo" atualiza a página e mostra o mesmo aviso para mim.
Blaze Gawlik
11

Você menciona o usuário alternando entre as atividades rapidamente. Pode ser que você esteja ligando unbindServiceantes que a conexão do serviço seja estabelecida? Isso pode ter o efeito de não conseguir desvincular e vazar a ligação.

Não tem muita certeza de como você poderia lidar com isso ... Talvez quando onServiceConnectedfor chamado, você possa ligar unbindServicese onDestroyjá tiver sido chamado. Não tenho certeza se isso vai funcionar.


Se ainda não o fez, você pode adicionar um método onUnbind ao seu serviço. Dessa forma, você pode ver exatamente quando suas classes se desvinculam e isso pode ajudar na depuração.

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

Tente usar unbindService () em OnUserLeaveHint (). Impede o cenário vazado do ServiceConnection e outras exceções.
Eu usei no meu código e funciona bem.

Ashwini Shahapurkar
fonte
1

Você pode controlá-lo apenas com um booleano; portanto, você só chama unbind se a ligação tiver sido feita

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 você deseja apenas desatá-lo, se estiver conectado

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;
    }
};
D4rWiNS
fonte
0

Todo serviço vinculado à atividade deve ser desvinculado no fechamento do aplicativo.

Então tente usar

 onPause(){
   unbindService(YOUR_SERVICE);
   super.onPause();
 }
Punit
fonte
0

Eu tenho lido sobre o Serviço Android muito recentemente e tive a chance de mergulhar nele. Eu encontrei um vazamento de serviço, para a minha situação aconteceu porque eu tinha um Serviço não vinculado que estava iniciando um Serviço vinculado , mas nesse serviço o meu não vinculado é substituído por uma Atividade .

Portanto, quando eu estava parando meu Serviço não vinculado usando stopSelf (), o vazamento ocorreu, o motivo foi que eu estava parando o serviço pai sem desvincular o serviço vinculado. Agora, o serviço vinculado está em execução e não sabe a quem pertence.

A solução fácil e direta é que você deve ligar para unbindService (YOUR_SERVICE); na sua função onDestroy () da Atividade / Serviço pai. Dessa forma, o ciclo de vida garantirá que seus serviços vinculados sejam parados ou limpos antes que a Atividade / Serviços pai seja desativada.

Há uma outra variação desse problema. Às vezes, no seu serviço vinculado, você deseja que certas funções funcionem apenas se o serviço estiver vinculado, por isso, acabamos colocando um sinalizador vinculado no onServiceConnected, como:

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

Isso funciona bem até aqui, mas o problema surge quando tratamos a função onServiceDisconnected como um retorno de chamada para a chamada de função unbindService ; isso, por documentação, é chamado apenas quando um serviço é morto ou travado . E você nunca receberá esse retorno de chamada no mesmo segmento . Portanto, acabamos fazendo algo como:

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

O que cria um erro grave no código porque nosso sinalizador encadernado nunca é redefinido para false e quando esse serviço é conectado novamente na maioria das vezes true. Portanto, para evitar esse cenário, defina boundcomo false no momento em que estiver chamando unbindService.

Isso é coberto com mais detalhes no blog de Erik .

A esperança que já chegou aqui deixou sua curiosidade satisfeita.

Farhaan Bukhsh
fonte
0

esse erro ocorre quando você vincula um serviço limitado. então, sol deve ser: -

  1. na conexão de serviço, adicione serviceBound como abaixo:

    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. serviço unbind onDestroy

        if (serviceBound) {
            unbindService(serviceConnection);
        }
Atef Farouk
fonte