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

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) { /* 业务逻辑处理 */ }

三、关键注意事项

  1. 编码统一:发送和接收必须使用相同的字符集(如UTF-8),避免文本乱码。
  2. 固定长度标识:使用固定长度的标识(如6字节),比可变长度+分隔符的方案更可靠,避免分隔符与数据内容冲突。
  3. 大文件处理:图片、音频、视频等大体积数据必须附加长度标识,否则接收端无法判断数据是否读取完毕,会一直阻塞在read()方法。
  4. 异常处理:必须捕获IO异常,处理连接断开、读取失败等场景,避免应用崩溃。

内容的提问来源于stack exchange,提问作者Nguyễn Minh Khoa

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 06:35:04