BindService () devuelve false pero unbindService () necesita ser llamado?
Mi aplicación utiliza un servicio proporcionado por otra (de mis) aplicaciones. Estoy usando un servicio vinculado con un Messenger
para acceder y comunicarse con él (y como es una aplicación diferente, también es un servicio remoto).
Cuando llamo a bindService
con una intención correcta, y la llamada devuelve false
(como se esperaba cuando el APK que proporciona el servicio no está a su alrededor), asumí de la documentación y el código de ejemplo, que no necesito unbind
la ServiceConnection
. Sin embargo, al hacerlo en mi dispositivo Galaxy Nexus (Jelly Bean), recibo el conocido mensaje ServiceConnectionLeaked
al finalizar la Activity
.
- Paho MQTT Actividad de activación del servicio de Android
- Android: ¿Cómo ejecutar el servicio cuando la aplicación es visible?
- Detención e inicio de un servicio basado en el estado de la aplicación
- Mantenga el servicio en funcionamiento incluso si el teléfono está apagado
- ¿Por qué utilizar un servicio Android?
He recuperado esto haciendo
if (!ctxt.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE)) { try { ctxt.unbindService(serviceConnection); } catch (Throwable t) {} // Clean up return; } // Store serviceConnection for future use
Soy curioso: ¿Acabo de extrañar algo en la documentación y se supone que funciona de esta manera? He añadido el try ... catch
para asegurarse de que incluso si este comportamiento es de hecho diferente en otros dispositivos o versiones de Android mi aplicación no es (negativamente) afectados por ella.
- Registrador de clave de Android
- Uso de ResultReceiver en Android
- Servicio de Android mantener vivo
- Silencio de Google Iniciar sesión en el servicio de fondo Android
- Servicio de Android e hilo de la interfaz de usuario
- Detectar si mi servicio de accesibilidad está habilitado
- Problema al ejecutar un script desde init.rc en el arranque del dispositivo
- Usar SharedPreferences en modo multiproceso
Generalmente, ServiceConnection siempre es asignado y registrado por el framework, independientemente de si la llamada a bindService()
devuelve true o false. Vea la implementación de bindService () en android.app.ContextImpl :
public boolean bindService(Intent service, ServiceConnection conn, int flags, int userHandle) { IServiceConnection sd; if (conn == null) { throw new IllegalArgumentException("connection is null"); } if (mPackageInfo != null) { // A new ServiceDispatcher will be created and registered along with // ServiceConnection in LoadedApk.mService for your application context. sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), mMainThread.getHandler(), flags); } else { throw new RuntimeException("Not supported in system context"); } try { ... ... return res != 0; } catch (RemoteException e) { return false; } }
Siempre debe desvincular el servicio cuando haya terminado con él, como sugiere la guía oficial de dev , como una buena forma de programación:
Para desconectarse del servicio, llame a unbindService ().
Cuando se destruye su cliente, se desvinculará del servicio, pero siempre debe desvincularse cuando haya terminado de interactuar con el servicio o cuando su actividad se detiene para que el servicio pueda apagarse mientras no se está utilizando. (Los tiempos apropiados para unir y desenlazar se discuten más abajo.)
ServiceConnectionLeaked se levanta cuando el marco inicia la realización de una limpieza final (por ejemplo, cuando se cierra la aplicación) y se detecta que hay ServiceConnection no registrado y el framework intentará desvincularlo para usted. Vea la implementación de removeContextRegistrations () en android.app.LoadedApk :
public void removeContextRegistrations(Context context, String who, String what) { final boolean reportRegistrationLeaks = StrictMode.vmRegistrationLeaksEnabled(); ... ... //Slog.i(TAG, "Receiver registrations: " + mReceivers); HashMap<ServiceConnection, LoadedApk.ServiceDispatcher> smap = mServices.remove(context); if (smap != null) { Iterator<LoadedApk.ServiceDispatcher> it = smap.values().iterator(); while (it.hasNext()) { LoadedApk.ServiceDispatcher sd = it.next(); ServiceConnectionLeaked leak = new ServiceConnectionLeaked( what + " " + who + " has leaked ServiceConnection " + sd.getServiceConnection() + " that was originally bound here"); leak.setStackTrace(sd.getLocation().getStackTrace()); Slog.e(ActivityThread.TAG, leak.getMessage(), leak); if (reportRegistrationLeaks) { StrictMode.onServiceConnectionLeaked(leak); } try { ActivityManagerNative.getDefault().unbindService( sd.getIServiceConnection()); } catch (RemoteException e) { // system crashed, nothing we can do } sd.doForget(); } } mUnboundServices.remove(context); //Slog.i(TAG, "Service registrations: " + mServices); }
- Hacer un icono de lanzador dinámico
- Android EditText: ¿Cómo aplicar la extensión de color de primer plano mientras escribe?