2013-09-02 22 views
8

Próbuję użyć usługi w Androidzie dla niektórych podstawowych operacji na bazie danych, ale z jakiegoś powodu otrzymuję informację o działaniu, które spowodowało błąd ServiceConnection. Opublikuję pełny odczyt Logcata na dole.ServiceConnectionLeaked w Androidzie

Muszę korzystać z tej samej usługi w wielu czynnościach, więc utworzyłem Superklasę do obsługi wszystkich zadań serwisowych. Wygląda to tak:

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

Chodzi o to, że aktywność dziecko nigdy nie będzie trzeba się martwić o połączenia z usługą lub nie, Nadklasa powinien dbać o pobieranie danych z usługi iz powrotem do dziecka.

Punkty Logcat doBindService() w onCreate() -> bindService (new Intent (this, global.FetchService.class), Connection, Context.BIND_AUTO_CREATE); jako linia powodująca błąd. Jednak usługa wycieka dopiero po uruchomieniu działania i jest widoczna przez dłużej niż 15 sekund, więc nie sądzę, aby funkcja onCreate() została wywołana.

Oto 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) 

Każda pomoc będzie mile widziana.

+0

Does ServiceConnectionLeaked wystąpić po opuszczeniu childActivity? Czy możesz umieścić instrukcje Log natychmiast po bindService i unbindService, aby upewnić się, że są one wywoływane jako dopasowane pary? –

+0

Może spróbuj wywołać doUnbindService() * przed * wywoływanie super.onPause() (w swojej metody onPause())? – Ponkadoodle

Odpowiedz

9

Podczas wywoływania doBindService() w onCreate() należy dodać do UnbindService() w onDestroy().

To działa dla mnie.

+0

Przepraszam, że zajęło mi to tyle czasu, aby odpowiedzieć. Dla osób przychodzących w przyszłości: rozwiązaniem jest, aby wywołania funkcjiBindService() i doUnbindService() były odzwierciedlane w cyklu życia aplikacji Android.Ponieważ wiązanie z usługą może trochę potrwać, należy to zrobić w onCreate() i onDestroy(). Robiłem to w onResume() i onPause(), ponieważ miałem paranoję na temat cyklu życia Androida. – MrMannWood

3

Dzwonisz doBindService() zarówno onCreate() i onResume(), próbując nazywając go po prostu w onResume() dopasować wezwanie do doUnbindService() w onPause()

+0

Właśnie wypróbowałem to i to nie zadziałało, Logcat teraz wskazuje do doBindService w onResume(). Nie spodziewałbym się, że to będzie problem, ponieważ moi booleanie powinni upewnić się, że połączenie nie zdarzy się za każdym razem. Usługa doBindService zapewnia zarówno, że a) usługa jest zawsze połączona, gdy aktywność jest widoczna, i b) usługa łączy się szybko, gdy czynność jest tworzona. – MrMannWood

1

trzeba użyć dobrego odniesienia dla aktywności getActivity() zwróci prąd jeden, i trzeba rozwiązać na ten, który zrobił bind

oto jak naprawiłem problem:

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

Otrzymujesz ten błąd, ponieważ usługa powiązana z aktywnością nie jest zatrzymywana po zniszczeniu tej czynności. Więc dlatego, że twoja usługa wciąż istnieje w pamięci i zużywa zasoby, co nic nie robi.

Aby rozwiązać ten problem, doBindService() połączenia w onCreate() i doUnbindService() w onDestroy()