如果不使用Inputstream读取蓝牙套接字,会发生阻塞现象

3
我正在开发一款与蓝牙设备通信的Android应用程序。
该设备不断向手机发送信息,但我选择只有在用户想要时才读取数据:通过按下启动/停止按钮。每次都会启动/停止一个读取服务,但连接保持打开状态。
连接设备很好,无论按下多少次启动/停止按钮,但只要用户让应用程序处于“停止”状态超过5秒钟,程序就会在下次按下“启动”按钮时卡在inputstream.read()。
我已经检查了套接字仍然是打开的。我知道read()是一个阻塞函数,但在这种情况下它不应该阻塞,因为设备正在不断发送数据。
有人遇到过类似的问题吗?可能问题确实来自于在几秒钟内未使用套接字吗?
以下是我用于获取数据的代码片段:
public void start() {
        if (isStarted()) {
            return;
        }
        task = taskService.submit(new Runnable() {
            @Override
            public void run() {
                int value;
                channel.reset();
                try {
                    while ((value = in.read()) != -1 && !Thread.currentThread().isInterrupted()) {
                        channel.put((byte) (value & 0xFF));
                    }
                } catch (IOException e) {
                    Log.d("STRS", "IO error : " + e.getMessage(), e);
                }
            }
        });

    }

  public void stop() {
        if (!isStarted()) {
            return;
        }
        task.cancel();
    }

    public boolean isStarted() {
        return task != null && !task.isDone();
    }

我猜你是通过中断线程来停止从流中读取数据,这可能会导致问题。另外,你是如何跟踪状态(已启动/已停止)的? - Titus
这个函数在一个读取服务中,每次用户按下开始/停止按钮时都会创建/销毁该服务,因此线程将每次都被创建和销毁。为什么会有问题?我编辑了我的帖子,包括isStarted函数。 - apat
иҝҷеҸҜиғҪжҳҜдёҖдёӘй—®йўҳпјҢеӣ дёәThreadзҡ„дёӯж–ӯж Үеҝ—еҸҜд»Ҙиў«еҸҰдёҖдёӘзәҝзЁӢжё…йҷӨпјҢдҪҶд»ҺжӮЁеҸ‘еёғзҡ„д»Јз ҒжқҘзңӢпјҢдјјд№Һ并йқһеҰӮжӯӨгҖӮжҲ‘зңӢеҲ°зҡ„дёҖдёӘй—®йўҳжҳҜпјҢжӮЁжІЎжңүдҪҝз”Ёд»»дҪ•еҗҢжӯҘжқҘи®ҫзҪ®/жЈҖжҹҘзҠ¶жҖҒгҖӮ - Titus
但是为什么这会导致程序在read()函数中卡住呢?而且只有在程序闲置几秒钟的情况下才会出现这种情况? - apat
TCP套接字也可能发生类似的情况,如果您不打算使用它,进入后台时应关闭连接。 - Nanoc
但是到底发生了什么?即使在“停止状态”期间我的应用程序没有使用套接字,但蓝牙设备仍然打开并使用它来发送信息。它是否因某种原因变得无响应? - apat
1个回答

1
我曾遇到过类似的问题,即无法从蓝牙套接字中阻塞式读取数据,而通过创建新线程,在紧密循环中调用read()函数并将数据读入循环缓冲区来解决该问题。现在你正在调用read()函数的线程从循环缓冲区中读取数据,因此是非阻塞的。
private class ReceiveThread extends Thread {

    private boolean running = true;

    public void stopThread() {
        running = false;
    }

    @Override
    public void run() {
        byte[] readBuffer = new byte[4 * 1024]; 

        while (running) {
            try {
                // write bytes directly into a circular buffer
                int numBytes = socket.read(readBuffer);

                if (numBytes > 0) {
                    circularBuffer.put(readBuffer, 0, numBytes);
                }
            } catch (InterruptedIOException e) {
                running = false;
            } catch (Exception e) {
                // swallow
            }
        }
    }
}

你可以直接从循环缓冲区中读取。
circularBuffer.get(buffer, 0, bytesToRead);

在Java中搜索循环缓冲区实现,有很多。只需确保它是线程安全的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接