检测 USB OTG 设备何时断开连接
Detect when a USB OTG device disconnects
我有一个与 USB OTG 设备交互的应用程序:
- 当 USB 设备连接时,助手 activity 会启动以显示 Android 确认对话框。这是通过清单中的
IntentFilter
完成的。
- 帮助程序 activity 启动服务是通过向其发送特定于应用程序的意图来启动的。
- 服务的
onCreate()
方法填充一个 IntentFilter
,添加服务在 运行 时应响应的操作,包括 UsbManager.ACTION_USB_DEVICE_DETACHED
。添加额外的调试输出告诉我该方法在我期望的时候运行,即当我注册接收器时 IntentFilter
被填充。
- 服务的
onStartCommand()
方法调用一个内部方法,该方法为意图过滤器注册 BroadcastReceiver
(如果服务是用启动意图启动的,并且具有必要的权限——否则服务终止).
- 当接收方收到
UsbManager.ACTION_USB_DEVICE_DETACHED
并且报告的设备是当前连接的设备时,它会停止服务。
- 还有一个mainactivity,不涉及处理USB设备。
- 该服务也会因其他原因而被调用,特别是在连接充电器时。在这种情况下,服务会查找蓝牙设备(如果 USB 设备已连接,由服务实例的成员指示为非空,则会跳过此操作并退出服务)。
现在,如果我插入 USB 设备,我会得到确认并启动服务,当我拔下设备时,服务会再次停止。到目前为止,还不错。
但是,在某些情况下,即使设备被拔掉,服务仍会保持 运行。我注意到当我连接设备时主 activity 打开时总是会发生这种情况。日志显示 服务从未收到 UsbManager.ACTION_USB_DEVICE_DETACHED
广播 。
在进行进一步测试时(打开主 activity 并在连接设备之前离开它),我发现证据表明 可能有两个服务实例 运行 出于某种原因。
这里发生了什么,我如何才能可靠地检测到 USB 设备已断开连接?
此行为似乎是由两个因素引起的:
- 如上所述,该服务不仅在 USB 设备连接时启动,而且在其他事件时启动,例如设备连接到交流适配器或主 activity 打开。在这些情况下,它将寻找蓝牙设备(“自动连接”)并在找到 none 或 USB 设备已连接时退出。
- 因此,当启用自动连接时,打开主 activity 将始终启动第一个服务实例。如果 USB 设备在 之后 连接,我们可能显然有两个服务实例 运行。我怀疑断开广播可能会被错误的实例接收到。
- 如果我禁用自动连接,该服务确实会收到断开连接事件但会忽略它,因为设备不被视为相等。然而日志输出显示两个设备的设备路径是相同的。进一步的分析表明,我只是简单地使用
!=
来比较两个 UsbDevice
实例,这未能捕获引用同一设备的两个不同 class 实例。
所以我们需要做两件事:
- 使用
UsbDevice#equals()
而不是相等运算符进行比较。
- 防止来自 运行 的服务的多个实例。确保在找不到设备时服务退出,并且将 Intent 传递给现有实例而不是启动新实例。
我有一个与 USB OTG 设备交互的应用程序:
- 当 USB 设备连接时,助手 activity 会启动以显示 Android 确认对话框。这是通过清单中的
IntentFilter
完成的。 - 帮助程序 activity 启动服务是通过向其发送特定于应用程序的意图来启动的。
- 服务的
onCreate()
方法填充一个IntentFilter
,添加服务在 运行 时应响应的操作,包括UsbManager.ACTION_USB_DEVICE_DETACHED
。添加额外的调试输出告诉我该方法在我期望的时候运行,即当我注册接收器时IntentFilter
被填充。 - 服务的
onStartCommand()
方法调用一个内部方法,该方法为意图过滤器注册BroadcastReceiver
(如果服务是用启动意图启动的,并且具有必要的权限——否则服务终止). - 当接收方收到
UsbManager.ACTION_USB_DEVICE_DETACHED
并且报告的设备是当前连接的设备时,它会停止服务。 - 还有一个mainactivity,不涉及处理USB设备。
- 该服务也会因其他原因而被调用,特别是在连接充电器时。在这种情况下,服务会查找蓝牙设备(如果 USB 设备已连接,由服务实例的成员指示为非空,则会跳过此操作并退出服务)。
现在,如果我插入 USB 设备,我会得到确认并启动服务,当我拔下设备时,服务会再次停止。到目前为止,还不错。
但是,在某些情况下,即使设备被拔掉,服务仍会保持 运行。我注意到当我连接设备时主 activity 打开时总是会发生这种情况。日志显示 服务从未收到 UsbManager.ACTION_USB_DEVICE_DETACHED
广播 。
在进行进一步测试时(打开主 activity 并在连接设备之前离开它),我发现证据表明 可能有两个服务实例 运行 出于某种原因。
这里发生了什么,我如何才能可靠地检测到 USB 设备已断开连接?
此行为似乎是由两个因素引起的:
- 如上所述,该服务不仅在 USB 设备连接时启动,而且在其他事件时启动,例如设备连接到交流适配器或主 activity 打开。在这些情况下,它将寻找蓝牙设备(“自动连接”)并在找到 none 或 USB 设备已连接时退出。
- 因此,当启用自动连接时,打开主 activity 将始终启动第一个服务实例。如果 USB 设备在 之后 连接,我们可能显然有两个服务实例 运行。我怀疑断开广播可能会被错误的实例接收到。
- 如果我禁用自动连接,该服务确实会收到断开连接事件但会忽略它,因为设备不被视为相等。然而日志输出显示两个设备的设备路径是相同的。进一步的分析表明,我只是简单地使用
!=
来比较两个UsbDevice
实例,这未能捕获引用同一设备的两个不同 class 实例。
所以我们需要做两件事:
- 使用
UsbDevice#equals()
而不是相等运算符进行比较。 - 防止来自 运行 的服务的多个实例。确保在找不到设备时服务退出,并且将 Intent 传递给现有实例而不是启动新实例。