studio bindservice android serviceconnection

studio - bindservice android



La actividad<Nombre de la aplicaciĆ³n> ha filtrado ServiceConnection<ServiceConnection Name> @ 438030a8 que originalmente estaba enlazado aquĆ­ (8)

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 de telnet. Las aplicaciones deben enlazarse a este servicio para enviar / recibir mensajes telnet.

Editar Gracias BDLS por su respuesta informativa. He vuelto a escribir mi código a la luz de su aclaración sobre la diferencia entre usar bindService () como una función independiente o después de startService (), y ahora solo recibo el mensaje de error de fuga intermitentemente cuando uso el botón Atrás para alternar entre ocupaciones.

Mi actividad de conexión tiene los siguientes 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 vinculan al servicio solo si se realizó una conexión exitosa (connectStatus == 1, guardado en preferencias compartidas). 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, la vinculación ocurre en onResume () para que recupere el estado modificado de la actividad de conexión, y en la función onDestroy () se desata, si es necesario.

Fin Editar

Pero sigo recibiendo el mensaje de error de pérdida de memoria "La actividad ha filtrado ServiceConnection @ 438030a8 que originalmente estaba enlazado aquí" de forma intermitente cuando se cambian las actividades. ¿Qué estoy haciendo mal?

Gracias de antemano por cualquier consejo o punteros!

Mensaje de error completo a continuación (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 segundo
Gracias de nuevo bdls por sus sugerencias. Hice lo que sugirió y agregué una anulación onUnBind () al servicio. onUnBind () solo se activa cuando todos los clientes se desconectan del servicio, pero cuando presiono el botón de inicio, se ejecuta y aparece el mensaje de error. Esto no tiene sentido para mí, ya que todos los clientes se han liberado del servicio, entonces, ¿cómo podría uno destruir 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 así como lo que dijiste, donde el enlace al servicio no está completo cuando se llama a unbindService (); sin embargo, traté de llamar a un método en el servicio cuando realicé una copia de seguridad de cada actividad para verificar que el enlace esté completo y todos pasaron bien.

En general, este comportamiento no parece estar relacionado con cuánto tiempo me quedo en cada actividad. Una vez que la primera actividad pierde su conexión de servicio, sin embargo, todos hacen lo que yo hice a través de ellos después de eso.

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

¿Algunas ideas?


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


Menciona al usuario alternar entre Actividades bastante rápido. ¿Podría ser que llame a unbindService antes de que se unbindService la conexión del servicio? Esto puede tener el efecto de no poder desvincularse, y luego filtrar el enlace.

No estoy del todo seguro de cómo podría manejar esto ... Tal vez cuando se llame unbindService podría llamar a unbindService si onDestroy ya ha sido llamado. Sin embargo, no estoy seguro de si eso funcionará.

Si aún no lo hizo, podría agregar un método onUnbind a su servicio. De esta forma, 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; }


No ha proporcionado ningún código de LightFactoryRemote , por lo que esto es solo una presunción, pero parece ser el tipo de problema que vería si estuviera usando el método bindService por sí mismo.

Para garantizar que un servicio se siga ejecutando, incluso después de que se haya llamado a su método llamado onDestroy , incluso antes de que la actividad haya comenzado, primero debe usar startService .

Los documentos de Android para el estado startService :

El uso de startService () anula el tiempo de vida del servicio predeterminado administrado por bindService (Intent, ServiceConnection, int): requiere que el servicio permanezca en ejecución hasta que se llame a stopService (Intent), independientemente de si hay clientes conectados.

Mientras que para bindService :

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

Entonces, lo que sucedió es que la actividad que vinculó (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 probablemente detiene el servicio).

Ejemplo

En este ejemplo, el servicio se debe seguir ejecutando 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.


Puedes simplemente controlarlo con un booleano, por lo que solo debes llamar desvincular 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 quieres 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; } };


Puedes usar:

@Override public void onDestroy() { super.onDestroy(); if (mServiceConn != null) { unbindService(mServiceConn); } }


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

Mira here .

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


Todos los servicios vinculados a la actividad deben desvincularse de la aplicación.

Entonces intenta usar

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


onResume en onResume pero desvincula en onDestroy . En su lugar, debe desvincular en onPause , de modo que siempre haya pares coincidentes de llamadas de vinculación / desvinculación. Sus errores intermitentes serán cuando su actividad se detenga pero no se destruya, y luego se reanudará nuevamente.