6

我的应用程序本质上是一个后台服务,需要偶尔注册一个NSD服务(Bonjour服务),以便能够发现由主后台服务(也就是应用程序运行)运行的套接字服务器。

如果我正确阅读了Android Bonjour Service 文档,这就是您启动Bonjour服务的方式(为简洁起见):

mNsdManager = Context.getSystemService(Context.NSD_SERVICE);
mDiscoveryListener = new NsdManager.DiscoveryListener()
mNsdManager.discoverServices(
        SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, mDiscoveryListener);

...这就是你阻止它的方式:

mNsdManager.unregisterService(mRegistrationListener);

这是我无法理解的部分:如果主服务突然关闭,Bonjour那么在崩溃时注册的任何服务都会继续运行,即使它不再有目的(它帮助发现的套接字服务器不是更长的时间)。

Bonjour当主服务重新启动时,我无法清理僵尸服务,因为mRegistrationListener最初注册的服务也不再存在。

我怀疑我采取了错误的方法:如何确保Bonjour在主服务崩溃后不会留下一堆僵尸服务?

4

2 回答 2

2

非特定于Android Bonjour,您可以尝试通过设置您的服务来处理崩溃,如此处答案中所述:我可以在我的应用程序崩溃之前调用方法吗

如果您无法将其设置为进行 unregisterService 调用,您应该能够将其设置为使用 ActivityManager 的 API killBackgroundProcesses。这需要向您的清单添加权限:

android.permission.KILL_BACKGROUND_PROCESSES
于 2015-12-14T18:44:22.303 回答
2

如果我理解正确,主要服务(带有服务器套接字的服务)Nsd在后台服务启动/停止发现服务时注册/取消注册Nsd服务。我认为这就是您所做的,因此您的“方法”是正确的。

关于这个问题,我应该欢迎您使用 Android Nsd。该框架有很多错误(您可以在其中找到您的问题),截至Android6.0 尚未修复这些错误,这使开发人员改用其他框架。

回到这个问题,你可能会尝试UncaughtExceptionHandler,只要记住所有回调都是由系统异步调用的,你可能会NPE在它调用时得到mRegistrationListener.onServiceUnregistered(),因为正如你所说,“它不再存在”

至于服务清理,理论上是可以的,但只有在NsdManager源代码自定义之后(需要更改一些方法的访问修饰符才能到达然后mRegistrationListener从另一个进程注销,这会导致将其从监听器映射中删除NsdManager) . 但是,如果要在市场上发布应用程序是没有任何意义的。

您可以尝试/尝试另一种解决方法。如果我没记错(可能记错了),必要的清理会在禁用Nsd. 我通过以下方式尝试过adb

// Disable
adb shell service call servicediscovery 2
// Enable
adb shell service call servicediscovery 2 i32 1

但是请注意,以编程方式进行这些调用可能并非易事,并且很可能需要 root,这再次限制了您的应用程序的受众。

关于killBackgroundProcesses()@thril 提出的方法,它以一个带有应用程序包名称的字符串作为参数。但servicediscovery它不是一个应用程序,它是一个系统服务。另外,您可以尝试在运行时杀死该进程(虽然我不知道是哪个),但要小心,您应该调查它给系统带来的影响,并确保在需要时再次启动该服务(自动通过系统或手动)。再次,需要做这个根。

总结答案,在继续之前Nsd,我强烈建议您搜索其功能/错误,以避免可能浪费您的时间和精力。除了上面提供的链接之外的一些参考资料:

  1. 禁用 Wifi 时未收到 NSD 设备丢失消息
  2. NsdManager 不会停止服务发现

PS 就我个人而言,在与多个Nsd框架错误作斗争之后,我最终编写了自己的框架。

于 2015-12-19T16:38:44.900 回答