在Android上的蓝牙中从InputStream读取数据时出错
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在Android上的蓝牙中从InputStream读取数据时出错相关的知识,希望对你有一定的参考价值。
我正在使用一个android应用程序,它使用蓝牙连接在我的Android智能手机和非Android蓝牙模块之间传输数据,使用SPP配置文件。我使用Android Developer网站的蓝牙聊天示例作为参考。
我已经成功地将两个设备相互连接,并将简单的字符串从智能手机发送到蓝牙模块。但是我在读取从模块发回的数据时遇到了一些错误。我使用以下代码,与蓝牙聊天示例完全相同,从InputStream读取数据
while (true) {
try {
// Read from the InputStream
bytes = mmInStream.read(buffer);
String str = new String(buffer);
Log.i(TAG, "mmInStream - " + str);
// Send the obtained bytes to the UI Activity
mHandler.obtainMessage(BluetoothChat.MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
} catch (IOException e) {
Log.e(TAG, "disconnected", e);
connectionLost();
break;
}
}
当我的蓝牙模块向手机发送一个简单的字符串时,没有正确接收该字符串。它以随机的方式分成几个部分。例如,如果我将三次“1234567890abcdef1234567890abcdef0123456789”发送到手机,Eclipse上的Logcat将记录这些:
mmInstream - 12345678910abcdef��������(continuing null)
mmInstream - 1��������(continuing null)
mmInstream - 2345678910abcdef0123456789��������(continuing null)
首次。在第二次和第三次传输数据时,它会收到差异:
mmInstream - 1234567891�������(continuing null)
mmInstream - 0abcdef012�������(continuing null)
mmInstream - 3456789���������(continuing null)
mmInstream - 1234567891����������������(continuing null)
mmInstream - 0abcdef0123456789������������(continuing null)
我不知道为什么会发生这种情况以及如何解决这个问题。如果以这样的任意方式接收数据,我无法获得必要的数据来处理。我怎样才能把它整理成一件?
任何帮助,将不胜感激。
非常感谢。
我注意到你的代码有两件事:
- 首先进一步发送到你的应用程序,你读取的缓冲区的引用并不总是一个很好的解决方案:如果在此期间缓冲区被覆盖怎么办? See this bug on stackoverflow for example您可以通过复制您从蓝牙读取的数据(例如使用buffer.clone())来绕过这一点,或者如果您不喜欢使用太多内存,则可以使读取缓冲区成为循环读取缓冲区。
- 您应该能够重新编译数据,即使它是在单独的数据包中接收(但是在短时间内收到数据包)。例如,您可以创建启动/停止标志。它仍然取决于您通过蓝牙发送的对象类型...
现在一个可能的解决方案,如果以前的2个警告没用,那就是:
而不是调用.read的无限循环 - 阻塞调用 - 你可以这样做:
while(true) {
if mmInStream.getAvailable()>0 {
-your read code here-
}
else SystemClock.sleep(100);
}
这是一个黑客,它有时可能仍然只读取消息的某些部分 - 但它将是非常罕见的!
如果有用,请投票/更正!
我有这个问题,我已经用这种方式解决了这个角色的问题
public void run() {
int bytes; // bytes returned from read()
int availableBytes = 0;
// Keep listening to the InputStream until an exception occurs
while (needRun) {
try {
availableBytes = mmInStream.available();
if(availableBytes > 0){
byte[] buffer = new byte[availableBytes]; // buffer store for the stream
// Read from the InputStream
bytes = mmInStream.read(buffer);
Log.d("mmInStream.read(buffer);", new String(buffer));
if( bytes > 0 ){
// Send the obtained bytes to the UI activity
mHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer).sendToTarget();
}
}
} catch (IOException e) {
Log.d("Error reading", e.getMessage());
e.printStackTrace();
break;
}
}
}
我使用了最后两个代码,它们运行良好,但是当连接丢失时,用户界面不会得到通知,因此状态不会更改为STATE_NONE。在我的情况下,我希望应用程序尝试在连接丢失时重新连接最后一个设备!在尝试了很多方法后,我终于以这种方式解决了问题:
- 我创建了一个END字符,这个字符我知道我永远不会使用,但只是在我发送的字符串的末尾。 “”是我的字符串字符的结尾。
- 我创建了一个临时字符串tmp_msg。
- 每次收到Stream时,都会从该Stream中创建第二个临时字符串“readMessage”。
- 搜索“readMessage”以查找结束字符(“。”)。
- 如果未检测到结束字符,则“readMessage”将连同到tmp_msg。因此,当第一次和第二次和第三次没有收到结束字符时tmp_msg = readMessage1 + readMessage2 + readMessage3。
- 当结束字符“。”如果检测到tmp_msg,则tmp_msg与最后读取的消息连接,并且从中构造字节“buffer”。
- 然后将“buffer”发送到用户界面,并将tmp_msg重新初始化为“”(空字符串)。这是整个代码:(不对BluetoothChat活动进行修改)。
public void run() { Log.i(TAG, "BEGIN mConnectedThread"); byte[] buffer = new byte[1024]; int bytes; // Keep listening to the InputStream while connected String tmp_msg =""; while (true) { try { // Read from the InputStream bytes = mmInStream.read(buffer); String readMessage = new String(buffer, 0,bytes); if (readMessage.contains(".")){ tmp_msg+=readMessage; byte[] buffer1 = tmp_msg.getBytes(); int bytes1=buffer1.length; tmp_msg=""; // Send the obtained bytes to the UI Activity mHandler.obtainMessage(BluetoothChat.MESSAGE_READ,bytes1,-1,buffer1).sendToTarget(); }else{ tmp_msg+=readMessage; } } catch (IOException e) { // Log.e(TAG, "disconnected", e); connectionLost(); // Start the service over to restart listening mode BluetoothChatService.this.start(); break; } } }
Radu的修复工作太棒了!我自己一直在使用蓝牙聊天示例代码处理这个问题很长一段时间。以下是我用来捕捉和显示远程传感器的温度读数:
// Keep listening to the InputStream while connected
while (true) {
try {
byte[] buffer = new byte[128];
String readMessage;
int bytes;
if (mmInStream.available()>2) {
try {
// Read from the InputStream
bytes = mmInStream.read(buffer);
readMessage = new String(buffer, 0, bytes);
}catch (IOException e) {
Log.e(TAG, "disconnected", e);
break;
}
// Send the obtained bytes to the UI Activity
mHandler.obtainMessage(HomeBlueRemote.MESSAGE_READ, bytes, -1, readMessage)
.sendToTarget();
}
else {
SystemClock.sleep(100);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
正如你所见,我将(buffer.available()> 0)修改为> 2.这是因为我的微控制器正在为温度发送2个字节。 。在此修复之前,字节计数的输入流会有所不同,有时只会捕获1个字节,这会破坏Android应用程序中的温度显示读数。再次,在网络上的所有建议,Radu有android输入流bug的最佳解决方法。
我找到了!
你必须重置缓冲区:
buffer = new byte [1024];
在这之前:
bytes = mmInStream.read(buffer);
至少它对我有用,并且不需要睡眠命令。
我认为有很多好的答案。我的贡献是,当进入蓝牙输入流时,每次处理一个数字,如下所示。这样做的目的是确保每组数据都是一个长度值(作为String),通过将每个新值(包含在主Activity Handler中的readMessage字符串中)放入List中,可以非常容易地处理它。这样,你就可以使用List(字符串)(编辑器不会让我使用<>的)对象通过提取通过提取来将数据处理回实数
Integer.valueOf(此处传递的List(String)对象)
//连接时继续监听InputStream while(true){
try {
byte[] buffer = new byte[1]; // make this one byte to pass one digit at a time through Bluetooth Handler
String readMessage;
int bytes;
if (mmInStream.available()>2) {
try {
// Read from the InputStream
bytes = mmInStream.read(buffer);
readMessage = new String(buffer, 0, bytes);
}catch (IOException e) {
Log.e(TAG, "disconnected", e);
break;
}
// Send the obtained bytes to the UI Activity
mHandler.obtainMessage(HomeBlueRemote.MESSAGE_READ, bytes, -1, readMessage)
.sendToTarget();
}
试试这个:
public void run() {
byte[] buffer;
ArrayList<Integer> arr_byte = new ArrayList<Integer>();
while (true) {
try {
int data = mmInStream.read();
if(mmInStream.available()>0) {
arr_byte.add(data);
} else {
arr_byte.add(data);
buffer = new byte[arr_byte.size()];
for(int i = 0 ; i < arr_byte.size() ; i++) {
buffer[i] = arr_byte.get(i).byteValue();
}
Log.e("INPUT",new String(buffer));
mHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
arr_byte = new ArrayList<Integer>();
}
} catch (IOException e) {
break;
}
}
}
我也有这个问题。现在工作得很好。没有 字符。
我的方式:我在MainActivity中构建一个textView,其id为txtReceive。
@Override
public void run() {
byte[] buffer=new byte[1024];
int bytes;
while(true) {
try {
bytes = inputStream.read(buffer);
final String strReceived = new String(buffer, 0, bytes);
runOnUiThread(new Runnable() {
@Override
public void run() {
txtReceive.append(strReceived);
}
});
} catch (Exception e) {
Log.d(TAG, "loi ");
以上是关于在Android上的蓝牙中从InputStream读取数据时出错的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Android 上从蓝牙的 InputStream 中读取
如果“x”时间已过,则创建一个取消 InputStream.read() 调用的线程