android - bindService() 返回 false 但需要调用 unbindService()?

标签 android service ipc

我的应用程序使用另一个(我的)应用程序提供的服务。我正在使用 bound service使用 Messenger 访问它并与其通信(由于它是一个不同的应用程序,它也是一个远程服务)。

当我以正确的 Intent 调用 bindService 时,调用返回 false(正如预期的那样,当提供服务的 APK 不存在时),我从文档中假设和示例代码,我不需要取消绑定(bind) ServiceConnection。但是,在我的 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 版本上确实不同,我的应用程序也不会(负面)受到它的影响。

最佳答案

一般来说,ServiceConnection 总是由框架分配和注册,无论 bindService() 调用返回 true 还是 false。请参见 android.app.ContextImpl 中的 bindService() 实现:

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

您应该始终在完成服务后解除绑定(bind),如 the official dev guide 所建议的那样,作为一种良好的编程方式:

  • To disconnect from the service, call unbindService().

    When your client is destroyed, it will unbind from the service, but you should always unbind when you're done interacting with the service or when your activity pauses so that the service can shutdown while its not being used. (Appropriate times to bind and unbind is discussed more below.)

当框架开始执行最终清理(例如,当您的应用程序退出时)并发现有未注册的 ServiceConnection 时,将引发 ServiceConnectionLeaked,然后框架将尝试为您解除绑定(bind)。请参阅 android.app.LoadedApk 中的 removeContextRegistrations() 实现:

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

关于android - bindService() 返回 false 但需要调用 unbindService()?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14255338/

相关文章:

android - travis-ci 构建因 ShellCommandUnresponsiveException 不断失败

android - 键盘与 facebook 登录屏幕重叠

android - 如何在android中改变芯片组件的形状?

java - 在 CentOs 中将 java 应用程序作为服务运行时遇到错误 : nested exception is java. lang.UnsatisfiedLinkError

Angular 2 : how to correctly change the template's variable via service?

java - Spring Boot 将 CrudRepository 注入(inject)服务

linux - IPC共享内存和线程内存的性能差异

c - 如何组织一个需要创建Window并退出的C程序?

c - 是否有可能以某种方式在 Docker 容器之间或容器与主机之间使用 POSIX 信号量?

android - Service 的 stopSelfResult 方法的目的是什么?真正的用例将是完美的。