2013-01-10 18 views
6

Moja aplikacja korzysta z usług innych (moich) aplikacji. Korzystam z bound service z Messenger, aby uzyskać do niego dostęp i komunikować się z nim (a ponieważ jest to inna aplikacja, jest to również usługa zdalna).bindService() zwraca wartość false, ale unbindService() musi zostać wywołana?

Kiedy zadzwonić bindService z właściwą intencją, a wywołanie zwraca false (zgodnie z oczekiwaniami, gdy APK świadczenia usługi nie ma w pobliżu), Przypuszczałem z dokumentacją i kodem przykład, że nie muszę się unbind na ServiceConnection. Jednak, kiedy robię to na moim urządzeniu Galaxy Nexus (Jelly Bean), otrzymuję dobrze znany komunikat ServiceConnectionLeaked po zakończeniu Activity.

mam uratowane, że wykonując

if (!ctxt.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE)) { 
    try { 
     ctxt.unbindService(serviceConnection); 
    } catch (Throwable t) {} 
    // Clean up 
    return; 
} 
// Store serviceConnection for future use 

jestem ciekaw: czy po prostu brakuje czegoś w dokumentacji i jest to ma działać w ten sposób? Dodałem try ... catch, aby upewnić się, że nawet jeśli to zachowanie jest rzeczywiście inne na innych urządzeniach lub wersjach Androida, moja aplikacja nie jest nim (negatywnie).

Odpowiedz

7

Mówiąc ogólnie, połączenie ServiceConnection jest zawsze przydzielane i rejestrowane przez framework, niezależnie od tego, czy wywołanie bindService() zwraca true czy false. Zobacz bindService() w 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; 
    } 
} 

Zawsze należy rozpiąć usługę, gdy jesteś z nim zrobić, jak sugeruje the official dev guide, jako dobrego programowania sposób:

  • Aby odłączyć z usługi, wywołaj polecenie unbindService().

    Kiedy twój klient zostanie zniszczony, będzie się on wiązał z usługą, ale zawsze powinieneś się odłączyć, kiedy skończysz wchodzić w interakcję z usługą lub gdy twoja aktywność zostanie wstrzymana, aby usługa mogła zostać zamknięta, gdy nie jest używana. (Odpowiednie czasy związać i unbind omówiono bardziej poniżej.)

The ServiceConnectionLeaked jest podniesiona, gdy ramy rozpoczęcie wykonywania ostatecznej oczyszczanie (na przykład, gdy aplikacja zostanie zamknięty) i stwierdził, że nie jest rejestrowana ServiceConnection, a framework spróbuje go rozwiązać. Zobacz removeContextRegistrations() wykonanie w 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); 
} 
+0

Dzięki za odpowiedź, ale to nadal nie jest zgodny z próbek (np RemoteService w ApiDemos czy też tylko rozpiąć jeśli 'onServiceConnected()' nazywano). Ponieważ jednak z twoją pomocą mogę teraz zobaczyć, że nawet opis wysokiego poziomu wydaje się dopuszczać taką interpretację, przyjmuję odpowiedź. – Stephan

Powiązane problemy