Android Kotlin蓝牙传输:如何识别接收数据类型并处理?
蓝牙异构数据传输:类型识别与解析方案
先明确结论:通过前置标识文本区分数据类型的思路完全可行,这是蓝牙跨设备传输不同类型数据的通用解决方案,能有效解决你当前接收端无法区分数据类型的问题。
核心实现思路
发送端在实际数据前附加固定的类型标识(如"TEXT:"、"IMAGE:"),接收端先读取标识判断数据类型,再根据类型执行对应的解析逻辑。针对大体积数据(图片/音频/视频),建议在标识后额外发送数据长度,确保接收端能完整读取所有数据。
一、发送端实现(Kotlin)
统一按「标识 + [数据长度] + 实际数据」的格式发送:
import android.bluetooth.BluetoothSocket import java.nio.ByteBuffer import java.nio.charset.Charsets // 发送文本数据 fun sendText(socket: BluetoothSocket, content: String) { val outputStream = socket.outputStream val typePrefix = "TEXT:".toByteArray(Charsets.UTF_8) val contentBytes = content.toByteArray(Charsets.UTF_8) // 先发送类型标识,再发送文本内容 outputStream.write(typePrefix) outputStream.write(contentBytes) outputStream.flush() } // 发送图片数据(带长度标识) fun sendImage(socket: BluetoothSocket, imageBytes: ByteArray) { val outputStream = socket.outputStream val typePrefix = "IMAGE:".toByteArray(Charsets.UTF_8) // 将数据长度转成4字节的ByteArray(Int占4字节) val lengthBytes = ByteBuffer.allocate(4).putInt(imageBytes.size).array() // 发送顺序:标识 → 数据长度 → 图片字节 outputStream.write(typePrefix) outputStream.write(lengthBytes) outputStream.write(imageBytes) outputStream.flush() } // 音频/视频的发送逻辑与图片一致,仅需替换标识为"AUDIO:"/"VIDEO:"
二、接收端实现(Kotlin)
先读取固定长度的类型标识,再根据标识分支处理数据:
import android.bluetooth.BluetoothSocket import android.graphics.BitmapFactory import java.nio.ByteBuffer import java.nio.charset.Charsets import java.io.ByteArrayOutputStream fun listenForBluetoothData(socket: BluetoothSocket) { val inputStream = socket.inputStream val buffer = ByteArray(1024) val charset = Charsets.UTF_8 val prefixLength = 6 // 所有标识的固定长度(如"TEXT:"/"IMAGE:"都是6个字符) while (true) { try { // 1. 读取类型标识 val prefixBuffer = ByteArray(prefixLength) val prefixReadCount = inputStream.read(prefixBuffer) if (prefixReadCount != prefixLength) { // 标识读取不完整(如连接断开),跳过本轮循环 continue } val dataType = String(prefixBuffer, charset).trim() // 2. 根据类型分支处理 when (dataType) { "TEXT:" -> { // 读取文本数据(循环读取所有可用字节) val textBos = ByteArrayOutputStream() var bytesRead: Int while (inputStream.available() > 0) { bytesRead = inputStream.read(buffer) textBos.write(buffer, 0, bytesRead) } val receivedText = String(textBos.toByteArray(), charset) // 处理接收到的文本 processReceivedText(receivedText) } "IMAGE:" -> { // 读取图片数据长度 val lengthBuffer = ByteArray(4) inputStream.read(lengthBuffer) val imageTotalLength = ByteBuffer.wrap(lengthBuffer).int // 读取完整的图片字节 val imageBuffer = ByteArray(imageTotalLength) var totalRead = 0 while (totalRead < imageTotalLength) { val bytesRead = inputStream.read(imageBuffer, totalRead, imageTotalLength - totalRead) if (bytesRead == -1) break // 连接断开,终止读取 totalRead += bytesRead } // 转成Bitmap处理 if (totalRead == imageTotalLength) { val bitmap = BitmapFactory.decodeByteArray(imageBuffer, 0, imageTotalLength) processReceivedImage(bitmap) } } // 扩展:音频/视频类型的处理逻辑与图片一致 } } catch (e: Exception) { // 捕获IO异常,处理连接断开场景 break } } } // 示例处理函数 private fun processReceivedText(text: String) { /* 业务逻辑处理 */ } private fun processReceivedImage(bitmap: android.graphics.Bitmap) { /* 业务逻辑处理 */ }
三、关键注意事项
- 编码统一:发送和接收必须使用相同的字符集(如UTF-8),避免文本乱码。
- 固定长度标识:使用固定长度的标识(如6字节),比可变长度+分隔符的方案更可靠,避免分隔符与数据内容冲突。
- 大文件处理:图片、音频、视频等大体积数据必须附加长度标识,否则接收端无法判断数据是否读取完毕,会一直阻塞在
read()方法。 - 异常处理:必须捕获IO异常,处理连接断开、读取失败等场景,避免应用崩溃。
内容的提问来源于stack exchange,提问作者Nguyễn Minh Khoa
相关产品推荐
相关产品推荐

