java - Android:蓝牙 - 如何读取传入数据

标签 java android multithreading bluetooth stream

我已成功与蓝牙设备配对并连接。我现在有兴趣接收在 2 之间传输的所有数据并查看是什么。

我正在从套接字获取输入流并尝试读取它。我退回并记录它。

根据我所读的内容,我知道这样做的唯一方法就是使用字节缓冲区进行读取以返回一个 int。但是我应该有大量数据通过。我怎样才能连续读出正在传输的数据,并将格式设置为字节而不是 int。

谢谢。

完整代码如下:

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();
    }
}

最佳答案

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

如果套接字发送/接收文本,执行此操作。

发送:

String text = "My message";
socketOutputStream.write(text.getBytes());

接收:

int length = socketInputStream.read(buffer);
String text = new String(buffer, 0, length);

socketOutputStream 应该是您的 bluetoothSocket.getOutputStream()

如果套接字发送/接收大量数据,关键是while循环防止内存不足异常。数据将按 block (例如每 4KB 缓冲区大小)读取,当您选择缓冲区大小时,请考虑堆大小,如果您是直播媒体,还要考虑延迟和质量。

发送:

int length;
while ((length = largeDataInputStream.read(buffer)) != -1) {
    socketOutputStream.write(buffer, 0, length);
}

接收:

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
    }
}

常见问题解答:

  • 如何获取接收数据的大小?您必须自己实现以通知远程设备准备好接收数据(包括文件大小),这将需要至少一个双套接字连接(2 个套接字,1 个设备),例如,1 个文本套接字 fragment 和自定义命令,以及 1 个用于大数据(如文件或流媒体)的套接字。
  • 什么是 largeDataInputStreamlargeDataOutputStream?这些流可以是普通的 I/O 流、FileInputStream/FileOutputStream 等。
  • 为什么 BluetoothSocket 的 while 循环永远不会结束?套接字输入持续接收数据,read() 方法会阻塞自身,直到检测到数据。为防止阻塞该行中的代码,必须中断 while 循环。

注意:此答案可能需要修改。我的母语不是英语。

关于java - Android:蓝牙 - 如何读取传入数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44593085/

相关文章:

Java : My error is a cannot find symbol in run method for Threads?

java - OpenGL "zoom": object clipping and brightness

java - 我的 AppWidgetProvider 会在 onReceive 中从 3rd 方应用程序接收数据的可能原因是什么?

android - Firebase Android 如何处理 onChildAdded

android - 如何为 Eclipse 设置 Android(ADT 插件)?

c# - 释放锁时出现 SynchronizationLockException(从未同步的代码块调用了对象同步方法。)

java - Collections.unmodificList 上的同步

c# - 手动锁定和同步方法之间的区别

java - GWT JSON 解析正在删除\字符

android - 我什么时候应该在 Android Studio 中使用 Android Project View 的每个选项?