2012-02-10 39 views
7

我有一个使用蓝牙接收来自其他设备的一些数据(字节)的应用程序。一切进展顺利,但我在收到所有字节时遇到了一个小问题。收到字节后,我会在Toast上显示它们,以便测试它们。当其它设备发送10个字节一起(例如:“ABCDEFGHIJ”),程序将采取的第一个字节的“A”仅,并显示在一个吐司,然后去第二次迭代和读出的其他9个字节,并显示“ BCDEFGHIJ“在吐司上。这里是我的代码:如何通过蓝牙一起读取所有字节?

byte[] buffer = new byte[1024]; // Read 1K character at a time. 
int bytes = 0; // Number of bytes. 

while(true) 
{ 
    try 
    { 
     // Read from the InputStream. 
     bytes = bInStream.read(buffer); 

     // Send the obtained bytes to the MainActivity. 
     mainActivityHandler.obtainMessage(MainActivity.MESSAGE_READ, bytes, -1, buffer).sendToTarget(); 
    } 
    catch(IOException e) 
    { 
     connectionLost(); 
     break; 
    } 
} 

在MainActivity,我有:

// The Handler that gets information back from the BluetoothManager. 
private final Handler handler = new Handler() 
{ 
    @Override 
    public void handleMessage(Message msg) 
    { 
     switch(msg.what) 
     { 
      case MESSAGE_READ: 
       byte[] readBuf = (byte[]) msg.obj; 

       // construct a string from the valid bytes in the buffer. 
       String readMessage = new String(readBuf, 0, msg.arg1); 
       Toast.makeText(MainActivity.this, readMessage, Toast.LENGTH_SHORT).show(); 
       break; 

      // ... 
     } 
    } 
}; 

我怎样才能收到所有字节在一起?

+0

我可以看到你是如何发送邮件?你在做类似bOutStream.write(“ABCDEFGHIJ” .getBytes()),或者是你写出来的人物之一,在一个时间? – broody 2012-02-10 17:03:11

+0

蓝牙模块连接到arduino,所以我使用arduino软件的串行监视器发送消息。 – 2012-02-10 17:12:37

回答

6

嗯最有可能的罪魁祸首是在你发送消息的方式。您的接收没有问题,它将接收到写入的字节数(最多1024)。

如果你有在邮件发送你也许可以一次读取一个字节,然后当你打一个预定义的终止给你一个处理消息的方式没有控制。例如:“ABCDEFGHIJ#”,其中#是终结符。

String msg = ""; 
byte ch; 
while((ch=mInStream.read())!='#') { 
    bytes++; 
    msg+=ch; 
} 
+0

+1好的解决方案。我会使用这个解决方案,直到我找到解决问题的另一种方法。谢谢! – 2012-02-10 17:41:28

+0

如果我传输二进制数据会怎么样?我如何确定终止符不是数据流的一部分? – stoefln 2015-05-14 14:49:01

4

蓝牙连接是基于流的,而不是基于分组。没有保证或试图保持分组化。所以任何数量的写入都会导致任意数量的读取,只是字节流保证是正确的。如果您需要检测数据包,则需要提供自己的数据包结构来包装数据。例如,在每个数据包前添加一个长度字段,以便您可以在接收端进行重构。

+0

+1这也是一个很好的解决方案。谢谢! – 2012-02-10 19:38:39

+0

@TJD我怎么知道长度字段的长度? – stoefln 2015-05-14 14:47:38

-1

处理时间长于缓冲区的信息(可能是危险的,如果从来没有清零,因为会占用你的内存)的一种方法是处理它们在大块:

String inString = ""; 
byte[] buffer = new byte[1024]; // buffer store for the stream 
int bytes; // bytes returned from read() 

while (true) { 
    try { 
     bytes = mmInStream.read(buffer); 
     String chunk = new String(buffer, 0, bytes); 
     if(chunk.contains(";")) 
     { 
      inString += chunk.substring(0,chunk.indexOf(';')); 
      Message msg = new Message(); 
      msg.obj = inString; 
      handler.sendMessage(msg); 
      inString = chunk.substring(chunk.indexOf(';')); 
     } 
     else 
     { 
      inString += chunk; 
     } 
    } catch (IOException e) { 
     break; 
    } 
} 
+0

它不能帮助我读取缓冲区内的所有消息 – 2014-08-13 02:58:03

+0

该代码假定';'是消息分隔符。代码是一个示例实现,并且不是通用的 - 你不能复制粘贴它,并期望在没有修改的情况下工作,但是显示了一个背后的概念。它读取所有消息。一旦消息结束,handler.sendMessage(msg);被调用来处理完整的消​​息,并继续处理缓冲区。您必须实现处理程序来处理/读取消息。这是概念 – 2014-08-13 08:16:24

2

从@broody接受的答案是正确的。但是,如果数据本身包含'#',则可能难以获取数据。所以,根据我的是附加的最佳方法“\ n”,然后“\ r”(或任何其他字符,这是不太可能拥有数据Refer ASCII Table),其中将数据发送到您的Android应用设备。它只是用作换行并标记数据结束。

如:ABCDEFGH \ n \ r

然后你的代码可以是这样的:

byte[] buffer = new byte[1024]; 
while (true) { 

     // Read from the InputStream 
      buffer[bytes] = (byte) mmInStream.read();     
     // Send the obtained bytes to the UI Activity 
if ((buffer[bytes] == '\n')||(buffer[bytes]=='\r')) 
{ 
    mHandler.obtainMessage(MainActivity.MESSAGE_READ, bytes, -1, buffer).sendToTarget(); 
    bytes=0; 
} 
else 
bytes++; 
} 

希望它可以帮助 问候

+0

**辉煌**!这解决了我的问题,而无需在Arduino端添加额外的'#'字符。我只是跳过了检查'\ r'(我只检查'\ n'),它的作用就像一个魅力。 – 2015-06-12 08:13:36