La actividad <Nombre de la aplicación> ha filtrado ServiceConnection <ServiceConnection Name> @ 438030a8 que originalmente estaba vinculado aquí

134

Estoy trabajando en mi primera aplicación de Android. Tengo tres actividades en mi aplicación, y el usuario cambia de un lado a otro con bastante frecuencia. También tengo un servicio remoto, que maneja una conexión telnet. Las aplicaciones deben vincularse a este servicio para enviar / recibir mensajes telnet.

Editar Gracias BDLS por su respuesta informativa. He reescrito mi código a la luz de su aclaración sobre la diferencia entre usarlobindService()como una función independiente o despuésstartService(), y ahora solo recibo el mensaje de error de fuga de manera intermitente cuando uso el botón Atrás para alternar entre actividades.

Mi actividad de conexión tiene lo siguiente 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()

Por lo tanto, el servicio se inicia cuando se inicia la actividad y se detiene cuando se destruye la actividad si no se realizó una conexión Telnet exitosa ( connectStatus == 0). Las otras actividades se unen al servicio solo si se realizó una conexión exitosa (se connectStatus == 1guardó en una preferencia compartida). Aquí está su 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()

Por lo tanto, el enlace ocurre de onResume()modo que recogerá el estado cambiado de la actividad de conexión, y en la onDestroy()función no está vinculado, si es necesario.

Fin de edición

Pero sigo recibiendo el mensaje de error de pérdida de memoria "La actividad ha filtrado ServiceConnection @ 438030a8 que originalmente estaba vinculada aquí" de forma intermitente al cambiar de actividad. ¿Qué estoy haciendo mal?

Gracias de antemano por cualquier consejo o punteros !!!

Sigue el mensaje de error completo (del 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 el 2do
Gracias una vez más bdls por sus sugerencias. Hice lo que sugirió y agregué unaonUnBind()anulación al servicio. onUnBind()en realidad solo se activa cuando todos los clientes se desconectan del servicio, pero cuando presiono el botón de inicio, se ejecuta, ¡entonces aparece el mensaje de error! Esto no tiene sentido para mí, ya que todos los clientes se han desvinculado del servicio, entonces, ¿cómo podría el destruido filtrar una conexión de servicio? Echale un vistazo:

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

Pensé que podría ser algo como lo dijiste, donde el enlace al servicio no está completo cuando unbindService()se llama, sin embargo, intenté llamar a un método en el servicio mientras hacía una copia de seguridad de cada actividad para verificar que el enlace estaba completo, y todos se fueron bien.

En general, este comportamiento no parece estar relacionado con el tiempo que permanezco en cada actividad. Sin embargo, una vez que la primera actividad pierde su serviceConnection, todos hacen lo mismo que los reviso después de eso.

Otra cosa, si enciendo "Destruir actividades inmediatamente" en Dev Tools, evita este error.

¿Algunas ideas?

catdotgif
fuente
¿Se puede agregar el código LightfactoryRemote.onCreate ()? (com.wingedvictorydesign.LightfactoryRemote.LightfactoryRemote.onCreate (LightfactoryRemote.java:97))
tbruyelle

Respuestas:

57

No ha proporcionado ninguno de sus códigos LightFactoryRemote, por lo que esto es solo una presunción, pero parece el tipo de problema que estaría viendo si estuviera usando el bindServicemétodo por sí mismo.

Para asegurarse de que un servicio se siga ejecutando, incluso después de que se haya onDestroyllamado su método a la actividad que comenzó , primero debe usarlo startService.

Los documentos de Android para el estado de startService :

El uso de startService () anula la vida útil predeterminada del servicio que administra bindService (Intent, ServiceConnection, int): requiere que el servicio permanezca ejecutándose hasta que se llame a stopService (Intent), independientemente de si hay algún cliente conectado a él.

Mientras que para bindService :

El servicio se considerará requerido por el sistema solo mientras exista el contexto de la llamada. Por ejemplo, si este contexto es una actividad que se detiene, no se requerirá que el servicio continúe ejecutándose hasta que se reanude la actividad.


Entonces, lo que sucedió es la actividad que unió (y por lo tanto inició) el servicio, se detuvo y, por lo tanto, el sistema cree que el servicio ya no es necesario y causa ese error (y luego probablemente lo detiene).


Ejemplo

En este ejemplo, el servicio debe mantenerse en ejecución independientemente de si la actividad de llamada se está ejecutando.

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

La primera línea inicia el servicio y la segunda lo vincula a la actividad.

bdls
fuente
Comienzo el servicio usando START_STICKY y también se inicia por la intención de arranque. Si llamo a StartService, crea otra instancia del servicio y no quiero que se ejecuten 2 servicios al mismo tiempo. ¿Cómo puedo solucionar el error en este caso?
opc0de
16
@ opc0de, no, no está creando otro servicio cuando llama a startService () dos veces. Los servicios son lógicamente únicos por naturaleza. No importa cuántas veces lo inicie, solo se ejecuta un servicio.
mahkie
2
¿Cuál es la solución para continuar el servicio en segundo plano para el reproductor de música?
Anand Savjani
45

Puedes usar:

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

    if (mServiceConn != null) {
        unbindService(mServiceConn);
    }
}
Mostafa Rostami
fuente
Excelente. Eso es lo que es.
Seltsam
31

Te onResumeatascas pero te desatas onDestroy. En su lugar, debe hacer la desvinculación onPause, de modo que siempre haya pares coincidentes de llamadas de vinculación / desvinculación. Sus errores intermitentes serán donde su actividad se detiene pero no se destruye, y luego se reanuda nuevamente.

Mella
fuente
13

Solo deberías necesitar desvincular el servicio onDestroy(). Entonces, la advertencia se irá.

Ver aquí .

Como el documento de Actividad intenta explicar, hay tres grupos principales de vinculación / desvinculación que usará: onCreate () y onDestroy (), onStart () y onStop (), y onResume () y onPause ().

pierrotlefou
fuente
77
como podría haber experimentado en Destroy casi nunca se llama desde el sistema operativo
martyglaubitz
Vea aquí el enlace hacia el contenido prohibido -> Advertencia de contenido prohibido. ¿Alguien puede acceder? El botón "Continuar para agrupar" simplemente actualiza la página y muestra la misma advertencia para mí.
Blaze Gawlik
11

Usted menciona que el usuario cambia entre Actividades bastante rápido. ¿Podría ser que está llamando unbindServiceantes de que se haya establecido la conexión de servicio? Esto puede tener el efecto de no desenlazarse y luego filtrar el enlace.

No estoy completamente seguro de cómo podría manejar esto ... Tal vez cuando onServiceConnectedse le llame podría llamar unbindServicesi onDestroyya se ha llamado. Sin embargo, no estoy seguro de si eso funcionará.


Si aún no lo ha hecho, puede agregar un método onUnbind a su servicio. De esa manera, puede ver exactamente cuándo sus clases se desvinculan de él, y podría ayudar con la depuración.

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

Intente usar unbindService () en OnUserLeaveHint (). Evita el escenario filtrado de ServiceConnection y otras excepciones.
Lo usé en mi código y funciona bien.

Ashwini Shahapurkar
fuente
1

Puede controlarlo con un valor booleano, por lo que solo puede llamar a unbind si se ha realizado un enlace

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;
    }
}

Si solo desea desvincularlo si se ha 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
fuente
0

Todos los servicios vinculados a la actividad deben estar desvinculados al cerrar la aplicación.

Intenta usar

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

He estado leyendo sobre el Servicio de Android muy recientemente y tuve la oportunidad de profundizar en él. Me he encontrado con una fuga de servicio, por mi situación sucedió porque tenía un Servicio sin vincular que estaba iniciando un Servicio vinculado , pero en este mi Servicio sin consolidar se reemplaza por una Actividad .

Entonces, cuando estaba deteniendo mi Servicio no vinculado usando stopSelf () , se produjo la fuga, la razón fue que estaba deteniendo el servicio principal sin desvincular el servicio vinculado. Ahora el servicio enlazado se está ejecutando y no sabe a quién pertenece.

La solución fácil y directa es que debe llamar a unbindService (YOUR_SERVICE); en la función onDestroy () de su Actividad / Servicio principal. De esta forma, el ciclo de vida garantizará que sus servicios vinculados se detengan o se limpien antes de que su Actividad / Servicios principal falle.

Hay otra variación de este problema. A veces, en su servicio enlazado, desea que ciertas funciones funcionen solo si el servicio está enlazado, por lo que terminamos colocando un indicador enlazado en onServiceConnected como:

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

Esto funciona bien hasta aquí, pero el problema viene cuando tratamos onServiceDisconnected función como una llamada de retorno para unbindService llamada de función, esto mediante la documentación sólo se invoca cuando un servicio se mató o se haya estrellado . Y nunca recibirá esta devolución de llamada en el mismo hilo . Por lo tanto, terminamos haciendo algo como:

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

Lo que crea un error importante en el código porque nuestra bandera enlazada nunca se restablece a falso y cuando este servicio se vuelve a conectar la mayoría de las veces lo es true. Entonces, para evitar este escenario, debe establecer el valor boundfalso en el momento en que llama unbindService.

Esta es la portada con más detalle en el blog de Erik .

Espero que quien haya venido aquí haya satisfecho su curiosidad.

Farhaan Bukhsh
fuente
0

este error ocurre cuando vas a vincular un servicio acotado. entonces, sol debería ser: -

  1. en la conexión de servicio, agregue serviceBound de la siguiente manera:

    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. desvincular el servicio en Destruir

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