java - Android BluetoothSocket - 超时

标签 java android multithreading bluetooth futuretask

我已经编写了一个用于连接外部配件的蓝牙 API。 API 的设计方式是有一堆阻塞调用,例如 getTimesetTimegetVolumesetVolume等 这些工作的方式是它们创建一个有效负载来发送和调用一个名为 sendAndReceive() 的方法,该方法会做一些准备工作并最终执行以下操作:

byte[] retVal = null;
BluetoothSocket socket = getSocket();
// write
socket.getOutputStream().write(payload);
// read response
if(responseExpected){
    byte[] buffer = new byte[1024]; // buffer store for the stream
    int readbytes = socket.getInputStream().read(buffer);
    retVal = new byte[readbytes];
    System.arraycopy(buffer, 0, retVal, 0, readbytes);
}
return retVal;

问题是有时此设备会变慢或无响应,因此我想在此调用上设置超时。 我尝试了几种将此代码放入线程\ future 任务并超时运行的方法,例如:

FutureTask<byte[]> theTask = null;
// create new task
theTask = new FutureTask<byte[]>(
        new Callable<byte[]>() {

            @Override
            public byte[] call() {
                byte[] retVal = null;
                BluetoothSocket socket = getSocket();
                // write
                socket.getOutputStream().write(payload);
                // read response
                if(responseExpected){
                    byte[] buffer = new byte[1024]; // buffer store for the stream
                    int readbytes = socket.getInputStream().read(buffer);
                    retVal = new byte[readbytes];
                    System.arraycopy(buffer, 0, retVal, 0, readbytes);
                }
                return retVal;
            }
        });

// start task in a new thread
new Thread(theTask).start();

// wait for the execution to finish, timeout after 6 secs
byte[] response;
try {
    response = theTask.get(6L, TimeUnit.SECONDS);
} catch (InterruptedException e) {
    throw new CbtException(e);
} catch (ExecutionException e) {
    throw new CbtException(e);
} catch (TimeoutException e) {
    throw new CbtCallTimedOutException(e);
}
    return response;
}

这种方法的问题是我不能在调用方法中重新抛出异常,并且由于某些方法抛出异常我想转发回 API 的客户端,所以我不能使用这种方法。

你能推荐一些其他的选择吗? 谢谢!

最佳答案

你正在保存你不能使用 Future<> 方法,因为你想重新抛出异常,但实际上这是可能的。

大多数在线示例确实使用原型(prototype) public 实现了 Callable ? call() 但只是将其更改为 public ? call() 抛出异常,一切都会好起来的:您将在 theTask.get() 调用中得到异常,您可以将其重新抛给调用者。

我个人使用 Executors 来处理 android 上的蓝牙套接字超时:

protected static String readAnswer(...)
throws Exception {
    String timeoutMessage = "timeout";
    ExecutorService executor = Executors.newCachedThreadPool();
    Callable<String> task = new Callable<String>() {
       public String call() throws Exception {
          return readAnswerNoTimeout(...);
       }
    };
    Future<String> future = executor.submit(task);
    try {
       return future.get(SOCKET_TIMEOUT_MS, TimeUnit.MILLISECONDS); 
    } catch (TimeoutException ex) {
        future.cancel(true);
        throw new Exception(timeoutMessage);
    }
}

关于java - Android BluetoothSocket - 超时,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6346649/

相关文章:

java - 用户 'root' @'localhost' 的访问被拒绝

java - CAS 身份验证后获取 JSF Managed Bean 中的 LDAP 属性

java - 进度条没有动画

android - 如何增加 Android Studio (MacOS High Sierra) 中的字体大小?

android - 以编程方式检索Google Ads版本

java - 从phonegap android连接到java服务器

android - 如果我单击 getview 内的 ListView 中的按钮,我希望我的两个 View 设置为可见

将多核合并为单核处理,在 linux 上,可能吗?

c# - nHibernate 在多个线程上枚举相同的集合

java - 多线程 FTP 输入流的输出不一致