2013-01-10 87 views
6

我的应用使用另一个(我的)应用提供的服务。我使用一个bound service机会Messenger来访问和通信它(因为它是一个不同的应用程序,它也是一个远程服务)。bindService()返回false,但需要调用unbindService()?

当我打电话bindService有一个适当的意图,该调用返回false(当APK提供服务不在身边如预期),我从文档和示例代码假设,我不需要unbindServiceConnection。然而,当我在Galaxy Nexus(Jelly Bean)设备上这样做时,我会在完成Activity时收到着名的ServiceConnectionLeaked消息。

我已经打捞上来的,这做

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

我很好奇:难道我只是想念的东西在文档中,并且它应该以这种方式工作?我添加了try ... catch以确保即使此行为在其他设备或Android版本上的确有所不同,我的应用程序也不会(受到其负面影响)。

回答

7

一般来说,无论bindService()调用返回true还是false,ServiceConnection总是由框架分配和注册。见bindService()实现在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; 
    } 
} 

你应该总是解除绑定的服务,当你用它做,通过the official dev guide的建议,作为一个良好的编程方式:

  • 要断开从服务中,调用unbindService()。

    当您的客户端被销毁时,它将从服务中解除绑定,但是当您完成与服务的交互时或者当您的活动暂停时应始终解除绑定,以便服务可以在不使用时关闭。 (适当的时候绑定和取消绑定更下面讨论。)时的框架开始进行最后的清理

的ServiceConnectionLeaked提高(例如,当您的应用程序退出),发现有未注册ServiceConnection,然后该框架将尝试为您解除绑定。见removeContextRegistrations()实现在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

感谢您的答复,但它仍然是不符合的样品是一致的(例如RemoteService在ApiDemos的确也只有解除绑定,如果'onServiceConnected()'叫)。但是,既然在你的帮助下,我现在可以看到,即使是高层次的描述似乎也允许这样的解释,我会接受答案。 – Stephan

相关问题