2013-09-02 7 views
8

Sto tentando di utilizzare un servizio in Android per alcune operazioni di base del database, ma per qualche motivo sto ricevendo un errore di ServiceConnection tra le attività. Pubblicherò la lettura completa di Logcat in fondo.ServiceConnectionLeaked in Android

Devo utilizzare lo stesso servizio in più attività, quindi ho creato una Superclasse per gestire tutte le attività di servizio. Ecco come si presenta:

private MyInterface child; 

public void onCreate(Bundle savedInstanceState, MyInterface child){ 
    super.onCreate(savedInstanceState); 

    doBindService(); 
} 

public void onResume(){ 
    super.onResume(); 

    doBindService(); 
} 

protected void onPause(){ 
    super.onPause(); 

    doUnbindService(); 
} 

private boolean bound; 
private boolean binding; 

ServiceConnection Connection = new ServiceConnection(){ 

    //called when the service is connected 
    @Override 
    public void onServiceConnected(ComponentName name, IBinder service) { 
     Log.d(LOGTAG, "Bound to Service"); 
     bound = true; 
     binding = false; 
     toServiceMessenger = new Messenger(service); 
     while(!commandsForService.isEmpty()){ 
      sendToService(commandsForService.poll()); 
     } 
    } 

    //called when the service is disconnected 
    @Override 
    public void onServiceDisconnected(ComponentName name) { 
     Log.d(LOGTAG, "Unboud from Service"); 
     bound = false; 
     binding = false; 
     toServiceMessenger = null; 
    } 
}; 

private boolean doBindService(){ 
    Log.d(LOGTAG, "Attempting to Bind to Service"); 
    if(!bound && !binding){ 
     binding = true; 
     bindService(new Intent(this, global.FetchService.class), Connection, Context.BIND_AUTO_CREATE); 
    } 
    return bound; 
} 

private void doUnbindService(){ 
    Log.d(LOGTAG, "Attempting to Unbind from Service"); 
    if(bound && !binding){ 
     binding = true; 
     unbindService(Connection); 
    } 
} 

public void sendToService(Message msg){ 
    if(bound){ 
     sendMessageToService(msg); 
    } 
    else{ 
     commandsForService.add(msg); 
    } 
} 

private void sendMessageToService(Message msg){ 
    if(bound){ 
     msg.replyTo = fromServiceMessenger; 
     try { 
      toServiceMessenger.send(msg); 
     } catch (RemoteException e) { 
      Log.d(LOGTAG, "RemoteException communicating with service"); 
     } 
    } 
    else{ 
     Log.d(LOGTAG, "Error: toServiceMessenger null while bound"); 
    } 
} 

L'idea è che l'attività del bambino non avrà mai bisogno di preoccuparsi di essere connessi al servizio o meno, la superclasse deve prendersi cura di ottenere i dati del servizio e di nuovo al bambino.

I punti Logcat doBindService() in onCreate() -> bindService (nuovo Intent (this, global.FetchService.class), Connection, Context.BIND_AUTO_CREATE); come la linea che causa l'errore. Tuttavia, il servizio perde solo dopo che l'attività è stata eseguita e visibile per più di 15 secondi, quindi non penso che onCreate() avrebbe dovuto essere chiamato.

Ecco il Logcat:

09-02 09:25:40.635: E/ActivityThread(5963): Activity childActivity has leaked ServiceConnection [email protected] that was originally bound here 
09-02 09:25:40.635: E/ActivityThread(5963): android.app.ServiceConnectionLeaked: Activity childActivity has leaked ServiceConnection [email protected] that was originally bound here 
09-02 09:25:40.635: E/ActivityThread(5963):  at android.app.LoadedApk$ServiceDispatcher.<init>(LoadedApk.java:1055) 
09-02 09:25:40.635: E/ActivityThread(5963):  at android.app.LoadedApk.getServiceDispatcher(LoadedApk.java:949) 
09-02 09:25:40.635: E/ActivityThread(5963):  at android.app.ContextImpl.bindService(ContextImpl.java:1472) 
09-02 09:25:40.635: E/ActivityThread(5963):  at android.app.ContextImpl.bindService(ContextImpl.java:1464) 
09-02 09:25:40.635: E/ActivityThread(5963):  at android.content.ContextWrapper.bindService(ContextWrapper.java:394) 
09-02 09:25:40.635: E/ActivityThread(5963):  at superClass.doBindService(FetchActivity.java:253) 
09-02 09:25:40.635: E/ActivityThread(5963):  at superClass.onCreate(FetchActivity.java:61) 
09-02 09:25:40.635: E/ActivityThread(5963):  at childActivity.onCreate(Showcase_Activity.java:37) 
09-02 09:25:40.635: E/ActivityThread(5963):  at android.app.Activity.performCreate(Activity.java:5066) 
09-02 09:25:40.635: E/ActivityThread(5963):  at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1101) 
09-02 09:25:40.635: E/ActivityThread(5963):  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2311) 
09-02 09:25:40.635: E/ActivityThread(5963):  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2391) 
09-02 09:25:40.635: E/ActivityThread(5963):  at android.app.ActivityThread.access$600(ActivityThread.java:151) 
09-02 09:25:40.635: E/ActivityThread(5963):  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1335) 
09-02 09:25:40.635: E/ActivityThread(5963):  at android.os.Handler.dispatchMessage(Handler.java:99) 
09-02 09:25:40.635: E/ActivityThread(5963):  at android.os.Looper.loop(Looper.java:155) 
09-02 09:25:40.635: E/ActivityThread(5963):  at android.app.ActivityThread.main(ActivityThread.java:5493) 
09-02 09:25:40.635: E/ActivityThread(5963):  at java.lang.reflect.Method.invokeNative(Native Method) 
09-02 09:25:40.635: E/ActivityThread(5963):  at java.lang.reflect.Method.invoke(Method.java:511) 
09-02 09:25:40.635: E/ActivityThread(5963):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1028) 
09-02 09:25:40.635: E/ActivityThread(5963):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:795) 
09-02 09:25:40.635: E/ActivityThread(5963):  at dalvik.system.NativeStart.main(Native Method) 

Ogni aiuto sarà molto apprezzato.

+0

fa ServiceConnectionLeaked dopo aver lasciato il childActivity? Potresti inserire istruzioni Log immediatamente dopo bindService e unbindService per assicurarti che vengano chiamate come coppie corrispondenti? –

+0

Forse prova a chiamare doUnbindService() * prima * chiamando super.onPause() (nel tuo metodo onPause())? – Ponkadoodle

risposta

9

Come si chiama lo doBindService() nello onCreate(), è necessario aggiungere il numero UnbindService() in onDestroy().

Funziona per me.

+0

Spiacente, mi ci è voluto così tanto tempo per rispondere. Per le persone che arrivano in futuro: la soluzione è che le chiamate a doBindService() e doUnbindService() dovrebbero essere speculari nel ciclo di vita dell'Android Activity.Poiché l'associazione a un servizio può richiedere del tempo, dovrebbe essere eseguita in onCreate() e onDestroy(). Lo stavo facendo in onResume() e onPause() perché ero paranoico riguardo al ciclo di vita di Android. – MrMannWood

3

che stai chiamando doBindService() sia onCreate() e onResume(), cercando di chiamare appena in onResume() per abbinare il vostro chiamata a doUnbindService() in onPause()

+0

Ho appena provato questo e non ha funzionato, il Logcat ora punta a doBindService in onResume(). Non mi aspetterei comunque che questo sia un problema, poiché i miei booleani dovrebbero assicurarsi che la chiamata non avvenga entrambe le volte. doBindService è in entrambi i casi per assicurarsi che a) il servizio sia sempre connesso quando l'attività è visibile e b) il servizio si connette rapidamente quando l'attività viene creata – MrMannWood

1

È necessario utilizzare il buon riferimento per l'attività getActivity() restituiscono l'attuale uno, ed è necessario separare su quello che ha fatto la legano

ecco come ho risolto il problema:

private Activity mActivity; 
    @Override 
    public void onStart() { 
     super.onStart(); 
     if (!mBound) { 
      startService(); 
      mActivity = getActivity(); 
     } 
    } 

    @Override 
    public void onStop() { 
     super.onStop(); 
     if (mBound && mActivity != null) { 
      mActivity.unbindService(mServiceConnection); 
      mActivity = null; 
     } 
    } 
1

Si riceve questo errore perché il servizio che si lega con l'attività non viene interrotto quando l'attività viene distrutta. Quindi, a causa di questo il tuo servizio è ancora presente in memoria e consuma risorse, che non sta facendo nulla.

per risolvere questo problema chiamata doBindService() in onCreate() e doUnbindService() in onDestroy() verifica