Android与Arduino Uno USB串口通信读取线程问题求助
解决Android USB Host读取Arduino数据的不完整与崩溃问题
看起来你已经走对了方向,但几个细节没处理好导致了数据截断和崩溃,我来帮你梳理并给出可行的实现方案:
问题根源分析
- 单次读取不完整:
bulkTransfer是单次USB批量传输调用,Arduino发送的"Try data"可能被拆分成多个数据包,单次调用只能拿到当前可用的部分数据,而且你没有用它的返回值(实际读取的字节数)来截取有效内容,导致把整个缓冲区的空字节也转成了字符串。 - 子线程直接更新UI:Android不允许在非主线程操作UI组件,你直接在读取线程里给
tv.text赋值,会触发CalledFromWrongThreadException,这就是无限循环时崩溃的原因。 - 无中断处理的死循环:没有给线程设置退出条件,一旦启动就无法正常终止,也没处理
bulkTransfer返回-1(传输错误)的情况,导致异常累积崩溃。
正确的读取线程实现
下面是修复后的Kotlin代码,包含完整的读取逻辑、UI安全更新和线程管理:
private var readerThread: Thread? = null private var isReading = false override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.your_layout) // 假设你已经完成了设备连接、endpointIn获取等初始化操作 startReading() } private fun startReading() { isReading = true readerThread = Thread { val buf = ByteArray(endpointIn.maxPacketSize) while (isReading && !Thread.currentThread().isInterrupted) { // 执行批量传输,获取实际读取的字节数 val bytesRead = connection.bulkTransfer(endpointIn, buf, buf.size, 1000) // 1秒超时 when { bytesRead > 0 -> { // 只截取有效字节转成字符串,避免空字符干扰 val receivedData = String(buf, 0, bytesRead).trim() // 在主线程更新UI runOnUiThread { tv.text = receivedData } } bytesRead == 0 -> { // 无数据可读,短暂休眠避免占用过多CPU Thread.sleep(100) } bytesRead == -1 -> { // 传输错误,可在这里添加错误处理逻辑 runOnUiThread { tv.text = "读取错误" } // 可选:停止读取或尝试重连 isReading = false } } } } readerThread?.start() } // 在Activity销毁时停止线程,避免内存泄漏 override fun onDestroy() { super.onDestroy() isReading = false readerThread?.interrupt() readerThread = null }
额外注意事项
- 权限与设备状态:确保你已经获取了USB设备的访问权限,并且在读取过程中设备没有断开连接,可以在
bytesRead == -1时触发重新连接逻辑。 - Arduino端优化:如果用Arduino的
Serial.println("Try data")会自动添加换行符,你可以在Android端用StringBuilder累积数据,直到遇到换行再更新UI,这样能更稳定地获取完整消息。 - 缓冲区复用:缓冲区声明在线程内部或外部复用都可以,核心是要用返回的
bytesRead确定有效数据长度,这才是解决你之前"只能读部分字符"的关键。
内容的提问来源于stack exchange,提问作者thapro
相关产品推荐
相关产品推荐

