java Android:蓝牙 - 如何读取传入的数据
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/44593085/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Android: Bluetooth - How to read incoming data
提问by
I have successfully paired and connected with a Bluetooth device. I am now interested in receiving all data being transferred between the 2 and seeing whats what.
我已成功与蓝牙设备配对并连接。我现在有兴趣接收在 2 之间传输的所有数据并查看是什么。
I am getting the input stream from the socket and attempting to read it. I return this and just log it.
我正在从套接字获取输入流并尝试读取它。我返回这个并记录它。
The only way I know of doing this from what I have read is just do read with a byte buffer to return an int. However I should have loads of data coming through. How can I continually read out data being transferred, and also format as bytes rather than an int.
我从我读过的内容中知道这样做的唯一方法就是使用字节缓冲区读取以返回一个整数。但是,我应该有大量数据通过。我怎样才能不断地读出正在传输的数据,并将格式设置为字节而不是整数。
Thanks.
谢谢。
Full code below:
完整代码如下:
public class ConnectThread {
private BluetoothSocketWrapper bluetoothSocket;
private BluetoothDevice device;
private boolean secure;
private BluetoothAdapter adapter;
private List<UUID> uuidCandidates;
private int candidate;
/**
* @param device the device
* @param secure if connection should be done via a secure socket
* @param adapter the Android BT adapter
* @param uuidCandidates a list of UUIDs. if null or empty, the Serial PP id is used
*/
public ConnectThread(BluetoothDevice device, boolean secure, BluetoothAdapter adapter,
List<UUID> uuidCandidates) {
this.device = device;
this.secure = secure;
this.adapter = adapter;
this.uuidCandidates = uuidCandidates;
if (this.uuidCandidates == null || this.uuidCandidates.isEmpty()) {
this.uuidCandidates = new ArrayList<UUID>();
this.uuidCandidates.add(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
}
}
public BluetoothSocketWrapper connect() throws IOException {
boolean success = false;
while (selectSocket()) {
adapter.cancelDiscovery();
try {
bluetoothSocket.connect();
success = true;
break;
} catch (IOException e) {
//try the fallback
try {
bluetoothSocket = new FallbackBluetoothSocket(bluetoothSocket.getUnderlyingSocket());
Thread.sleep(500);
bluetoothSocket.connect();
success = true;
break;
} catch (FallbackException e1) {
Log.w("BT", "Could not initialize FallbackBluetoothSocket classes.", e);
} catch (InterruptedException e1) {
Log.w("BT", e1.getMessage(), e1);
} catch (IOException e1) {
Log.w("BT", "Fallback failed. Cancelling.", e1);
}
}
}
if (!success) {
throw new IOException("Could not connect to device: "+ device.getAddress());
}
receiveData(bluetoothSocket);
return bluetoothSocket;
}
private boolean selectSocket() throws IOException {
if (candidate >= uuidCandidates.size()) {
return false;
}
BluetoothSocket tmp;
UUID uuid = uuidCandidates.get(candidate++);
Log.i("BT", "Attempting to connect to Protocol: "+ uuid);
if (secure) {
tmp = device.createRfcommSocketToServiceRecord(uuid);
} else {
tmp = device.createInsecureRfcommSocketToServiceRecord(uuid);
}
bluetoothSocket = new NativeBluetoothSocket(tmp);
return true;
}
public static interface BluetoothSocketWrapper {
InputStream getInputStream() throws IOException;
OutputStream getOutputStream() throws IOException;
String getRemoteDeviceName();
void connect() throws IOException;
String getRemoteDeviceAddress();
void close() throws IOException;
BluetoothSocket getUnderlyingSocket();
}
public static class NativeBluetoothSocket implements BluetoothSocketWrapper {
private BluetoothSocket socket;
public NativeBluetoothSocket(BluetoothSocket tmp) {
this.socket = tmp;
}
@Override
public InputStream getInputStream() throws IOException {
return socket.getInputStream();
}
@Override
public OutputStream getOutputStream() throws IOException {
return socket.getOutputStream();
}
@Override
public String getRemoteDeviceName() {
return socket.getRemoteDevice().getName();
}
@Override
public void connect() throws IOException {
socket.connect();
}
@Override
public String getRemoteDeviceAddress() {
return socket.getRemoteDevice().getAddress();
}
@Override
public void close() throws IOException {
socket.close();
}
@Override
public BluetoothSocket getUnderlyingSocket() {
return socket;
}
}
public class FallbackBluetoothSocket extends NativeBluetoothSocket {
private BluetoothSocket fallbackSocket;
public FallbackBluetoothSocket(BluetoothSocket tmp) throws FallbackException {
super(tmp);
try
{
Class<?> clazz = tmp.getRemoteDevice().getClass();
Class<?>[] paramTypes = new Class<?>[] {Integer.TYPE};
Method m = clazz.getMethod("createRfcommSocket", paramTypes);
Object[] params = new Object[] {Integer.valueOf(1)};
fallbackSocket = (BluetoothSocket) m.invoke(tmp.getRemoteDevice(), params);
}
catch (Exception e)
{
throw new FallbackException(e);
}
}
@Override
public InputStream getInputStream() throws IOException {
return fallbackSocket.getInputStream();
}
@Override
public OutputStream getOutputStream() throws IOException {
return fallbackSocket.getOutputStream();
}
@Override
public void connect() throws IOException {
fallbackSocket.connect();
}
@Override
public void close() throws IOException {
fallbackSocket.close();
}
}
public static class FallbackException extends Exception {
/**
*
*/
private static final long serialVersionUID = 1L;
public FallbackException(Exception e) {
super(e);
}
}
public void sendData(BluetoothSocketWrapper socket, int data) throws IOException{
ByteArrayOutputStream output = new ByteArrayOutputStream(4);
output.write(data);
OutputStream outputStream = socket.getOutputStream();
outputStream.write(output.toByteArray());
}
public int receiveData(BluetoothSocketWrapper socket) throws IOException{
byte[] buffer = new byte[256];
ByteArrayInputStream input = new ByteArrayInputStream(buffer);
InputStream inputStream = socket.getInputStream();
inputStream.read(buffer);
return input.read();
}
}
回答by
In the first place, stop using ByteArrayInputStream
and ByteArrayOutputStream
for more control.
首先,停止使用ByteArrayInputStream
并ByteArrayOutputStream
获得更多控制。
If the socket sends/receives text, do this.
如果套接字发送/接收文本,请执行此操作。
TO SEND:
发送:
String text = "My message";
socketOutputStream.write(text.getBytes());
TO RECEIVE:
接收:
int length = socketInputStream.read(buffer);
String text = new String(buffer, 0, length);
The socketOutputStream
should be your bluetoothSocket.getOutputStream()
.
本socketOutputStream
应该是你的bluetoothSocket.getOutputStream()
。
If the socket sends/receives large loads of data, the key is the while loop to prevent out of memory exceptions. The data will be read by chunks of (for example every 4KB of buffer size), when you choose the buffer size, consider the heap size, if you're live-streaming media, consider latency and quality too.
如果套接字发送/接收大量数据,关键是防止内存不足异常的 while 循环。数据将按块读取(例如每 4KB 的缓冲区大小),当您选择缓冲区大小时,请考虑堆大小,如果您是实时流媒体,还要考虑延迟和质量。
TO SEND:
发送:
int length;
while ((length = largeDataInputStream.read(buffer)) != -1) {
socketOutputStream.write(buffer, 0, length);
}
TO RECEIVE:
接受:
int length;
//socketInputStream never returns -1 unless connection is broken
while ((length = socketInputStream.read(buffer)) != -1) {
largeDataOutputStream.write(buffer, 0, length);
if (progress >= dataSize) {
break; //Break loop if progress reaches the limit
}
}
FAQ:
常问问题:
- How do I get the size of receiving data? You'll have to make your own implementation to notify remote device to get ready to receive data (including file size), this will require at least a dual-socket connection (2 sockets, 1 device), for example, 1 socket for text fragments and custom commands, and 1 socket for large data, like files or streaming.
- What are
largeDataInputStream
andlargeDataOutputStream
? These streams can be normal I/O streams,FileInputStream
/FileOutputStream
or etc. - Why the while loop for
BluetoothSocket
never finishes? The socket input is continuously receiving data, and theread()
methods blocks itself until data is detected. To prevent blocking the code in that line, while loop must be broken.
- 如何获取接收数据的大小?您必须自己实现来通知远程设备准备好接收数据(包括文件大小),这至少需要一个双套接字连接(2 个套接字,1 个设备),例如,1 个用于文本的套接字片段和自定义命令,以及 1 个用于大数据(如文件或流媒体)的套接字。
- 什么是
largeDataInputStream
和largeDataOutputStream
?这些流可以是普通的 I/O 流,FileInputStream
/FileOutputStream
或等等。 - 为什么 while 循环
BluetoothSocket
永远不会结束?套接字输入不断地接收数据,并且这些read()
方法会阻塞自己直到检测到数据。为了防止阻塞该行中的代码,必须打破 while 循环。
NOTE:This answer could need an edit. I'm not a native English speaker.
注意:此答案可能需要编辑。我的母语不是英语。
回答by
Following the above advice, I am now using this code to retrieve data.
按照上述建议,我现在使用此代码来检索数据。
public void receiveData(BluetoothSocketWrapper socket) throws IOException{
InputStream socketInputStream = socket.getInputStream();
byte[] buffer = new byte[256];
int bytes;
// Keep looping to listen for received messages
while (true) {
try {
bytes = socketInputStream.read(buffer); //read bytes from input buffer
String readMessage = new String(buffer, 0, bytes);
// Send the obtained bytes to the UI Activity via handler
Log.i("logging", readMessage + "");
} catch (IOException e) {
break;
}
}
}