Android与Arduino USB通信问题:BroadcastReceiver Intent为空
Android USB设备权限广播Intent为空问题解决
核心问题分析
- 时序逻辑错误:
UsbConnection构造函数中调用usbManager.requestPermission()后立刻检查deviceIntent,此时用户尚未处理权限弹窗,BroadcastReceiver未触发,deviceIntent必然为空。 - Receiver注册滞后:先实例化
UsbConnection(触发权限请求)再注册BroadcastReceiver,可能导致权限广播无法被接收。 - 初始化逻辑前置:未拿到权限和设备信息时就尝试初始化
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
相关产品推荐
相关产品推荐

