You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android与Arduino USB通信问题:BroadcastReceiver Intent为空

Android USB设备权限广播Intent为空问题解决

核心问题分析

  1. 时序逻辑错误:UsbConnection构造函数中调用usbManager.requestPermission()后立刻检查deviceIntent,此时用户尚未处理权限弹窗,BroadcastReceiver未触发,deviceIntent必然为空。
  2. Receiver注册滞后:先实例化UsbConnection(触发权限请求)再注册BroadcastReceiver,可能导致权限广播无法被接收。
  3. 初始化逻辑前置:未拿到权限和设备信息时就尝试初始化UsbDeviceConnection、UsbInterface等对象,直接引发空指针相关错误。

修复步骤及代码调整

1. 调整Receiver注册时机

在MainActivity中先注册BroadcastReceiver,再初始化UsbConnection,确保权限广播能被正常捕获。

2. 重构设备初始化逻辑

将设备连接、接口初始化逻辑从构造函数中移出,放到权限通过后的回调方法中,避免提前执行无效操作。

3. 修正BroadcastReceiver逻辑

移除冗余空判断,确保权限通过后正确初始化设备连接。


修改后的MainActivity

package com.example.maturaproject02;

import static com.example.maturaproject02.UsbConnection.ACTION_USB_PERMISSION;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbManager;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;

import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.floatingactionbutton.FloatingActionButton;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

    UsbConnection usbConnection;
    private static final String TAG = "UsbConnection";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 先注册Receiver,再初始化USB连接
        IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
        this.registerReceiver(usbReceiver, filter);

        try {
            usbConnection = new UsbConnection(this);
        } catch (UsbConnection.noUsbDeviceException e) {
            throw new RuntimeException(e);
        }

        // RecyclerView初始化逻辑保留不变
        RecyclerView recyclerView = findViewById(R.id.rvChatItems);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));

        int verticalSpacing = 1;
        VerticalSpacingItemDecorator itemDecorator = new VerticalSpacingItemDecorator(verticalSpacing);
        recyclerView.addItemDecoration(itemDecorator);

        ContactAdapter contactAdapter = new ContactAdapter(this);
        recyclerView.setAdapter(contactAdapter);

        FloatingActionButton addContactButton = findViewById(R.id.addContactButton);
        addContactButton.setOnClickListener(v -> {
            View view1 = LayoutInflater.from(this).inflate(R.layout.input_name_layout, null);
            EditText newName = view1.findViewById(R.id.newName);
            AlertDialog alertDialog = new MaterialAlertDialogBuilder(this)
                    .setTitle("Kontakt benennen")
                    .setView(view1)
                    .setPositiveButton("OK", (dialog, which) -> {
                        String name = newName.getText().toString();
                        View view2 = LayoutInflater.from(this).inflate(R.layout.input_id_layout, null);
                        EditText newID = view2.findViewById(R.id.newID);
                        AlertDialog alertDialog2 = new MaterialAlertDialogBuilder(this)
                                .setTitle("ID setzen")
                                .setView(view2)
                                .setPositiveButton("OK", (dialog2, which2) -> {
                                    int id = Integer.parseInt(newID.getText().toString());
                                    Contact newContact = new Contact(name, id, new ArrayList<>());
                                    contactAdapter.addContact(newContact);
                                })
                                .setNegativeButton("Abbrechen", null)
                                .create();
                        alertDialog2.show();
                    })
                    .setNegativeButton("Abbrechen", null)
                    .create();
            alertDialog.show();
        });
    }

    private final BroadcastReceiver usbReceiver = new BroadcastReceiver() {
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (ACTION_USB_PERMISSION.equals(action)) {
                synchronized (this) {
                    UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
                    boolean permissionGranted = intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false);

                    if (permissionGranted) {
                        if (device != null) {
                            Toast.makeText(context, "权限已授予,初始化设备连接", Toast.LENGTH_SHORT).show();
                            usbConnection.initDeviceConnection(device);
                        }
                    } else {
                        Toast.makeText(context, "设备权限被拒绝: " + device, Toast.LENGTH_SHORT).show();
                        Log.d(TAG, "permission denied for device " + device);
                    }
                }
            }
        }
    };

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(usbReceiver);
    }
}

修改后的UsbConnection类

package com.example.maturaproject02;

import android.app.PendingIntent;
import android.content.Context;
import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbManager;
import android.widget.Toast;

import java.util.HashMap;

public class UsbConnection {

    public static final String ACTION_USB_PERMISSION = "com.example.maturaproject02.USB_PERMISSION";
    private UsbManager usbManager;
    private UsbDevice usbDevice;
    private UsbDeviceConnection usbDeviceConnection;
    private UsbInterface usbInterface;
    private UsbEndpoint usbEndpointIn;
    private UsbEndpoint usbEndpointOut;
    private PendingIntent permissionIntent;
    private Context context;

    public static class noUsbDeviceException extends Exception {
        public noUsbDeviceException(String message) {
            super(message);
        }
    }

    public UsbConnection(Context context) throws noUsbDeviceException {
        this.context = context;
        usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
        permissionIntent = PendingIntent.getBroadcast(context, 0, new Intent(ACTION_USB_PERMISSION), PendingIntent.FLAG_IMMUTABLE);

        HashMap<String, UsbDevice> deviceList = usbManager.getDeviceList();
        if (!deviceList.isEmpty()) {
            usbDevice = deviceList.values().iterator().next();
            usbManager.requestPermission(usbDevice, permissionIntent);
        } else {
            throw new noUsbDeviceException("未找到USB设备");
        }
    }

    // 权限通过后调用,初始化设备连接
    public void initDeviceConnection(UsbDevice device) {
        this.usbDevice = device;

        usbDeviceConnection = usbManager.openDevice(usbDevice);
        if (usbDeviceConnection == null) {
            Toast.makeText(context, "无法打开USB设备连接", Toast.LENGTH_SHORT).show();
            return;
        }

        usbInterface = usbDevice.getInterface(0);
        if (usbInterface == null) {
            Toast.makeText(context, "未找到USB接口", Toast.LENGTH_SHORT).show();
            return;
        }

        // 声明接口权限
        if (!usbDeviceConnection.claimInterface(usbInterface, true)) {
            Toast.makeText(context, "无法获取USB接口权限", Toast.LENGTH_SHORT).show();
            return;
        }

        // 查找输入输出端点
        for (int i = 0; i < usbInterface.getEndpointCount(); i++) {
            UsbEndpoint endpoint = usbInterface.getEndpoint(i);
            if (endpoint.getDirection() == UsbConstants.USB_DIR_IN) {
                usbEndpointIn = endpoint;
            } else {
                usbEndpointOut = endpoint;
            }
        }

        Toast.makeText(context, "USB设备初始化成功", Toast.LENGTH_SHORT).show();
    }

    public void write(String message) {
        if (usbDeviceConnection != null && usbEndpointOut != null) {
            usbDeviceConnection.bulkTransfer(usbEndpointOut, message.getBytes(), message.length(), 1000);
        }
    }

    public byte[] read() {
        byte[] bytes = new byte[usbEndpointIn != null ? usbEndpointIn.getMaxPacketSize() : 0];
        if (usbDeviceConnection != null && usbEndpointIn != null) {
            usbDeviceConnection.bulkTransfer(usbEndpointIn, bytes, bytes.length, 1000);
        }
        return bytes;
    }
}

额外注意事项

  • 在AndroidManifest.xml中添加USB权限声明:
<uses-feature android:name="android.hardware.usb.host" />
<uses-permission android:name="android.permission.USB_PERMISSION" />
  • API 33+需额外添加POST_NOTIFICATIONS权限,确保权限弹窗正常显示。
  • 确认Arduino使用的USB串口芯片(如CH340、FT232)已被Android系统识别,必要时可添加设备VID/PID过滤逻辑。

内容的提问来源于stack exchange,提问作者seaarebee

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 14:09:53