Android设备插入USB后UsbDevice始终返回null问题求助
解决UsbDevice始终返回null的问题
关键问题排查与修复
以下是导致你代码中UsbDevice始终为null的核心问题及对应修复方案:
1. Manifest中USB_DETACHED Action拼写错误
原代码中USB_DEVICE_DETACHED的Action开头多打了一个n,导致系统无法识别该广播:
<!-- 错误写法 --> <action android:name="anandroid.hardware.usb.action.USB_DEVICE_DETACHED" /> <!-- 修正后 --> <action android:name="android.hardware.usb.action.USB_DEVICE_DETACHED" />
2. 自定义Action常量错误
你定义的ACTION_USB_ATTACHED和ACTION_USB_DETACHED值重复,且未使用系统标准Action,导致广播接收器无法正确响应设备连接/断开事件:
// 错误写法 private val ACTION_USB_DETACHED = "com.android.example.USB_DEVICE.DETACHED" private val ACTION_USB_ATTACHED = "com.android.example.USB_DEVICE.DETACHED" // 修正后:直接使用系统标准常量 private val ACTION_USB_ATTACHED = UsbManager.ACTION_USB_DEVICE_ATTACHED private val ACTION_USB_DETACHED = UsbManager.ACTION_USB_DEVICE_DETACHED
3. 设备获取逻辑不完整
仅通过启动Intent获取设备的方式有局限性:当App不是被USB连接触发启动时,intent?.getParcelableExtra会返回null。需要主动遍历设备列表查找目标设备:
// 新增方法:遍历设备列表匹配目标设备 private fun findTargetDevice(): UsbDevice? { manager?.deviceList?.values?.forEach { usbDevice -> // 匹配device_filter中定义的vendorId和productId if (usbDevice.vendorId == 1234 && usbDevice.productId == 5678) { return usbDevice } } return null } // 在onCreate中调用:优先从Intent获取,失败则主动查找 device = intent?.getParcelableExtra(UsbManager.EXTRA_DEVICE) ?: findTargetDevice()
4. 广播接收器未处理核心逻辑
原广播接收器对设备连接/断开事件、权限请求结果均无处理,导致无法更新设备实例或感知权限状态:
private val usbReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { when (intent.action) { ACTION_USB_ATTACHED -> { // 设备连接时重新获取实例并检查权限 device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE) ?: findTargetDevice() device?.let { checkAndRequestPermission(it) } } ACTION_USB_DETACHED -> { // 设备断开时清空实例 device = null Toast.makeText(context, "USB设备已断开", Toast.LENGTH_SHORT).show() } ACTION_USB_PERMISSION -> { // 处理权限请求结果 val usbDevice = intent.getParcelableExtra<UsbDevice>(UsbManager.EXTRA_DEVICE) if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) { usbDevice?.let { device = it Toast.makeText(context, "权限获取成功", Toast.LENGTH_SHORT).show() // 此处可开始设备通信逻辑 } } else { Toast.makeText(context, "权限获取失败", Toast.LENGTH_SHORT).show() } } } } }
5. USB角色与连接场景误解
你提到将设备连接至电脑/充电器时返回null,这属于正常情况:
- 连接电脑:此时Android设备是USB外设,电脑是主机,Android端无法获取自己的
UsbDevice实例。 - 连接充电器:充电器仅提供供电,无数据通信功能,不会被识别为USB设备。
- 若要获取
UsbDevice,需将Android设备作为USB主机,通过OTG线外接USB外设(如U盘、传感器等)。
完整修正后的代码
AndroidManifest.xml
<intent-filter> <action android:name="android.hardware.usb.action.USB_DEVICE_DETACHED" /> </intent-filter> <intent-filter> <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" /> </intent-filter> <meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" android:resource="@xml/device_filter" />
device_filter.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <usb-device vendor-id="1234" product-id="5678" class="255" subclass="66" protocol="1" /> </resources>
MainActivity.kt
class MainActivity : AppCompatActivity() { private val ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION" private val ACTION_USB_ATTACHED = UsbManager.ACTION_USB_DEVICE_ATTACHED private val ACTION_USB_DETACHED = UsbManager.ACTION_USB_DEVICE_DETACHED private var filter: IntentFilter? = null private var manager: UsbManager? = null private var permissionIntent: PendingIntent? = null private var device: UsbDevice? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) manager = getSystemService(Context.USB_SERVICE) as UsbManager permissionIntent = PendingIntent.getBroadcast( this, 0, Intent(ACTION_USB_PERMISSION), if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { PendingIntent.FLAG_IMMUTABLE } else { PendingIntent.FLAG_UPDATE_CURRENT } ) // 初始化IntentFilter并注册广播接收器 filter = IntentFilter().apply { addAction(ACTION_USB_ATTACHED) addAction(ACTION_USB_DETACHED) addAction(ACTION_USB_PERMISSION) } registerReceiver(usbReceiver, filter) // 获取设备实例 device = intent?.getParcelableExtra(UsbManager.EXTRA_DEVICE) ?: findTargetDevice() device?.let { checkAndRequestPermission(it) } ?: run { Toast.makeText(applicationContext, "未检测到目标USB设备", Toast.LENGTH_SHORT).show() } } // 查找目标USB设备 private fun findTargetDevice(): UsbDevice? { manager?.deviceList?.values?.forEach { usbDevice -> if (usbDevice.vendorId == 1234 && usbDevice.productId == 5678) { return usbDevice } } return null } // 检查并请求权限 private fun checkAndRequestPermission(device: UsbDevice) { if (!manager!!.hasPermission(device)) { manager?.requestPermission(device, permissionIntent) } else { Toast.makeText(applicationContext, "已获取设备权限", Toast.LENGTH_SHORT).show() } } private val usbReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { when (intent.action) { ACTION_USB_ATTACHED -> { device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE) ?: findTargetDevice() device?.let { checkAndRequestPermission(it) } } ACTION_USB_DETACHED -> { device = null Toast.makeText(context, "USB设备已断开", Toast.LENGTH_SHORT).show() } ACTION_USB_PERMISSION -> { val usbDevice = intent.getParcelableExtra<UsbDevice>(UsbManager.EXTRA_DEVICE) if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) { usbDevice?.let { device = it Toast.makeText(context, "权限获取成功", Toast.LENGTH_SHORT).show() } } else { Toast.makeText(context, "权限获取失败", Toast.LENGTH_SHORT).show() } } } } } override fun onDestroy() { super.onDestroy() unregisterReceiver(usbReceiver) } }
内容的提问来源于stack exchange,提问作者Ahmet Yılmaz
相关产品推荐
相关产品推荐

