Android:正在连接USB设备,等待权限

Android: connecting to USB device, wait for permission

我正在尝试这样做:连接到 USB 设备并获取打开的(或失败的)连接。我根据我找到的例子和解释做了逻辑,但我在等待许可授予时遇到了问题。首先,我尝试了一种使用 wait()+notifyAll() 的 "good" 方式,而不是尝试直接循环检查,但两次等待方法 (waitConnection()) 都阻塞了我给它的超时,而且只有之后收到了消息。所以我尝试了这两个版本。

  1. wait/notifyAll:

    public UsbConnector startConnection(Context context) {
    
    BroadcastReceiver receiver = new BroadcastReceiver() {
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (ACTION_USB_PERMISSION.equals(action)) {
                synchronized (syncObj) {
                    if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
                        UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
                        if (device != null) {
                            if (device.getVendorId() == vendorId && device.getProductId() == productId) {
                                connection = usbManager.openDevice(device);
                                connectedDevice = device;
                            }
                        }
                    }
                    syncObj.notyfyAll();
                }
            }
        }
    };
    
    try {
        usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
        for (final UsbDevice device : usbManager.getDeviceList().values()) {
            if (device.getVendorId() == this.vendorId && device.getProductId() == this.productId) {
    
                context.registerReceiver(receiver, new IntentFilter(ACTION_USB_PERMISSION));
                usbManager.requestPermission(device,
                        PendingIntent.getBroadcast(context, 0, new Intent(ACTION_USB_PERMISSION), 0));
                break;
            }
        }
    } catch (Exception e) {
    }
    return this;
    }
    
    public UsbDeviceConnection waitConnection(int timeout) {
    try {
        Thread.sleep(10, 0);
        syncObj.wait(timeout);
    } catch (InterruptedException e) {
    }
    return getConnection();
    }
    
  2. 直接循环

    public UsbConnector startConnection(Context context) {
    
    BroadcastReceiver receiver = new BroadcastReceiver() {
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (ACTION_USB_PERMISSION.equals(action)) {
                synchronized (this) {
                    if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
                        UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
                        if (device != null) {
                            if (device.getVendorId() == vendorId && device.getProductId() == productId) {
                                connection = usbManager.openDevice(device);
                                connectedDevice = device;
                            }
                        }
                    }
                    permissionRequested = false;
                }
            }
        }
    };
    
    try {
        permissionRequested = false;
        usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
        for (final UsbDevice device : usbManager.getDeviceList().values()) {
            if (device.getVendorId() == this.vendorId && device.getProductId() == this.productId) {
    
                permissionRequested = true;
                context.registerReceiver(receiver, new IntentFilter(ACTION_USB_PERMISSION));
                usbManager.requestPermission(device,
                        PendingIntent.getBroadcast(context, 0, new Intent(ACTION_USB_PERMISSION), 0));
                break;
            }
        }
    } catch (Exception e) {
    }
    return this;
    }
    
    public UsbDeviceConnection waitConnection(int timeout) {
    int waited = timeout;
    while (permissionRequested && waited > 0) {
        try {
            Thread.sleep(10, 0);
        } catch (InterruptedException e) {
        }
        waited -= 10;
    }
    
    return getConnection();
    }
    

所以在这两种情况下,根据日志,waitConnection() 方法(由消费者在 startConnection() 之后立即调用)似乎阻止了执行(我给它超时 10 秒,它被阻止了10 秒),仅在完成后,BroadcastReceiver 才收到消息。看起来 requestPermission() 不是异步的(正如我认为的那样),但在这种情况下, startConnection() 怎么可能在收到消息之前立即退出?我如何等待 BroadcastReceiver 收到消息?假设我不使用 waitConnection() 方法,我的消费者应该如何知道它何时可以开始检查连接可用性?

"and only right after it's completed, the BroadcastReceiver gets the message"

默认情况下,onReceived 回调在主线程上调用。听起来您也在主线程上调用 waitConnection() 。由于 waitConnection() 块,主线程无法处理任何其他消息,直到 waitConnection() returns。这意味着在 waitConnection() 超时之前不会调用 onReceived

阻塞主线程通常不是一个好主意。 Read here

相反,您可以 onReceive 启动一个新的 activity,然后在获得 USB 许可后执行您需要执行的任何操作。这可能是也可能不是您的最佳解决方案,但无论如何,这里的关键是永远不要阻塞主线程。