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 == 1
guardó 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?
fuente
Respuestas:
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 elbindService
método por sí mismo.Para asegurarse de que un servicio se siga ejecutando, incluso después de que se haya
onDestroy
llamado su método a la actividad que comenzó , primero debe usarlostartService
.Los documentos de Android para el estado de startService :
Mientras que para bindService :
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.
La primera línea inicia el servicio y la segunda lo vincula a la actividad.
fuente
Puedes usar:
fuente
Te
onResume
atascas pero te desatasonDestroy
. En su lugar, debe hacer la desvinculaciónonPause
, 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.fuente
Solo deberías necesitar desvincular el servicio
onDestroy()
. Entonces, la advertencia se irá.Ver aquí .
fuente
Usted menciona que el usuario cambia entre Actividades bastante rápido. ¿Podría ser que está llamando
unbindService
antes 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
onServiceConnected
se le llame podría llamarunbindService
sionDestroy
ya 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.
fuente
Intente usar unbindService () en OnUserLeaveHint (). Evita el escenario filtrado de ServiceConnection y otras excepciones.
Lo usé en mi código y funciona bien.
fuente
Puede controlarlo con un valor booleano, por lo que solo puede llamar a unbind si se ha realizado un enlace
Si solo desea desvincularlo si se ha conectado
fuente
Todos los servicios vinculados a la actividad deben estar desvinculados al cerrar la aplicación.
Intenta usar
fuente
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:
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:
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 valorbound
falso en el momento en que llamaunbindService
.Esta es la portada con más detalle en el blog de Erik .
Espero que quien haya venido aquí haya satisfecho su curiosidad.
fuente
este error ocurre cuando vas a vincular un servicio acotado. entonces, sol debería ser: -
en la conexión de servicio, agregue serviceBound de la siguiente manera:
};
desvincular el servicio en Destruir
fuente