Android USB_STATE广播检测异常:连接断开均提示设备已断开
我使用以下代码检测USB设备的连接与断开状态:
IntentFilter filter = new IntentFilter(); filter.addAction("android.hardware.usb.action.USB_STATE"); context.registerReceiver(new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if(action.equalsIgnoreCase("android.hardware.usb.action.USB_STATE")) { //Check if change in USB state if (intent.getExtras().getBoolean("connected")) { Toast.makeText(context, "connect USB", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(context, "Disconnect!", Toast.LENGTH_SHORT).show(); } } } }, filter);但连接数码钢琴键盘后再断开,两种操作均提示“Disconnect!”,请问问题出在哪里?
问题原因
android.hardware.usb.action.USB_STATE 广播的connected字段,仅标识USB数据连接状态(比如USB调试、MTP文件传输这类数据交互场景),而非USB设备的物理连接状态。数码钢琴属于USB HID类设备(输入设备),连接后不会触发系统的USB数据连接状态变更,因此无论设备连接还是断开,connected字段始终返回false,导致你看到统一的“Disconnect!”提示。
解决方案
要检测USB HID设备(如数码钢琴键盘)的物理连接/断开,需使用专门的设备插拔广播:android.hardware.usb.action.USB_DEVICE_ATTACHED 和 android.hardware.usb.action.USB_DEVICE_DETACHED,具体实现步骤如下:
1. 配置Manifest权限与广播接收器
在AndroidManifest.xml中添加USB相关权限及静态广播注册:
<uses-feature android:name="android.hardware.usb.host" /> <uses-permission android:name="android.permission.USB_PERMISSION" /> <receiver android:name=".UsbDeviceReceiver"> <intent-filter> <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" /> <action android:name="android.hardware.usb.action.USB_DEVICE_DETACHED" /> </intent-filter> <meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" android:resource="@xml/usb_device_filter" /> </receiver>
2. 创建设备过滤规则
在res/xml目录下新建usb_device_filter.xml,配置你的数码钢琴的VID(厂商ID)和PID(产品ID),可通过adb shell dumpsys usb命令查看设备的VID/PID:
<?xml version="1.0" encoding="utf-8"?> <resources> <usb-device vendor-id="你的设备VID" product-id="你的设备PID" /> </resources>
3. 编写广播接收器代码
实现自定义广播接收器处理设备插拔事件:
public class UsbDeviceReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (action == null) return; switch (action) { case UsbManager.ACTION_USB_DEVICE_ATTACHED: Toast.makeText(context, "USB设备已连接", Toast.LENGTH_SHORT).show(); break; case UsbManager.ACTION_USB_DEVICE_DETACHED: Toast.makeText(context, "USB设备已断开", Toast.LENGTH_SHORT).show(); break; } } }
如果偏好动态注册广播(适合临时监听场景),可在Activity/Fragment中添加如下代码,但需注意动态注册的广播在App退至后台时可能被系统回收:
IntentFilter filter = new IntentFilter(); filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED); filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED); registerReceiver(new UsbDeviceReceiver(), filter);
内容的提问来源于stack exchange,提问作者M. Feyz

