我有一个与USB OTG设备交互的应用:
- 当USB设备连接时,助手活动开始显示Android确认对话框。这是通过清单中的
IntentFilter
完成的。 - 辅助活动开始服务是通过发送特定于应用的特定意图来开始服务的。
- 服务的
onCreate()
方法填充了IntentFilter
,并添加了运行时服务应反应的操作,包括UsbManager.ACTION_USB_DEVICE_DETACHED
。添加额外的调试输出告诉我当我期望它的方法时,即当我注册接收器时填充IntentFilter
。 - 服务的
onStartCommand()
方法调用了一种内部方法,该方法为Intert Filter注册BroadcastReceiver
(如果服务启动以开始意图启动,并且具有必要的权限,那么服务终止了服务)。
。
- 当接收器接收
UsbManager.ACTION_USB_DEVICE_DETACHED
并且报告的设备是当前连接的设备时,它会停止服务。 - 也有主要活动,该活动不涉及处理USB设备。
- 由于其他原因,该服务还被召集,特别是当连接充电器时。在这种情况下,服务寻找蓝牙设备(如果已经连接了USB设备,由服务实例的成员表示为非null,则会跳过并退出服务)。
现在,如果我插入USB设备,我将获得确认并启动服务,当我拔下设备时,服务再次停止。到目前为止,一切都很好。
但是,在某些情况下,即使在设备拔下设备之后,该服务仍保持运行。我注意到,当我连接设备时,当主活动打开时,总是会发生这种情况。日志向我展示该服务永远不会接收UsbManager.ACTION_USB_DEVICE_DETACHED
广播。
在进行进一步测试(打开主要活动并在连接设备之前远离它)时,我发现出于某种原因,运行的服务可能有两个实例。
这里发生了什么,我如何可靠地检测到USB设备已断开连接?
此行为似乎是由两个因素引起的:
- 如上所述,该服务不仅在USB设备连接时就可以启动,还可以在其他事件(例如已连接到AC适配器的设备或打开的主要活动)上开始。在这些情况下
- 结果,当启用自动连接时,打开主要活动将始终启动第一个服务实例。如果USB设备在之后连接,那么我们显然可能会运行两个服务实例。我怀疑断开的广播可能会被错误的实例所吸收。
- 如果我禁用AutoConnect,则该服务确实会接收断开事件,但会忽略它,因为设备不相同。然而,日志输出显示两个设备的设备路径相同。进一步的分析表明,我只是使用
!=
比较了两个UsbDevice
实例,该实例未能捕获两个不同的类实例,参考了同一设备。
所以我们需要做两件事:
- 使用
UsbDevice#equals()
而不是相等性操作员进行比较。 - 防止多个服务实例运行。确保在找不到设备并将意图交付到现有实例而不是启动新的实例时,请确保服务退出。