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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 08:15:54  来源:igfitidea点击:

Android: Bluetooth - How to read incoming data

javaandroidmultithreadingbluetoothstream

提问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 ByteArrayInputStreamand ByteArrayOutputStreamfor more control.

首先,停止使用ByteArrayInputStreamByteArrayOutputStream获得更多控制。

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 socketOutputStreamshould 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 largeDataInputStreamand largeDataOutputStream? These streams can be normal I/O streams, FileInputStream/FileOutputStreamor etc.
  • Why the while loop for BluetoothSocketnever finishes? The socket input is continuously receiving data, and the read()methods blocks itself until data is detected. To prevent blocking the code in that line, while loop must be broken.
  • 如何获取接收数据的大小?您必须自己实现来通知远程设备准备好接收数据(包括文件大小),这至少需要一个双套接字连接(2 个套接字,1 个设备),例如,1 个用于文本的套接字片段和自定义命令,以及 1 个用于大数据(如文件或流媒体)的套接字。
  • 什么是largeDataInputStreamlargeDataOutputStream?这些流可以是普通的 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;
        }
    }

}