蓝牙在Android上:我的Socket.connect()永远阻止,而Socket.close不会解锁

Jos*_*ams 7 sockets android bluetooth blocking

我一直在研究一款适用于Android的蓝牙应用程序,我刚刚发现了这个问题.当我mySocket.connect();在我的蓝牙服务类中进行预处理时,它偶尔会无限期地阻塞.我阅读了文档,BluetoothSocket.close()并说明了以下内容:

立即关闭此套接字,并释放所有相关资源.

导致其他线程中此套接字上的被阻止调用立即抛出IOException.

但是,这对我来说似乎不起作用.这是我设置计时器然后尝试连接的代码.

//code for starting timer and connecting
    MyRunnable runner = new MyRunnable(mySocket);
    Thread countThread = new Thread(runner);
    countThread.start();

    mySocket.connect();
    runner.setSocketConnected();


//code for MyRunnable
    private class MyRunnable implements Runnable{
        private boolean didSocketConnect = false;
        private boolean socketConnectFailed = false;
        private BluetoothSocket socket;

        public MyRunnable(BluetoothSocket socket){
            this.socket = socket;
        }

        public void run() {
            long start = System.currentTimeMillis();
            while(ESTABLISH_TIMEOUT + start >= System.currentTimeMillis() && !didSocketConnect && !socketConnectFailed){

            }
            if(!didSocketConnect && !socketConnectFailed){
                Log.v(TAG,"Reached Timeout and socket not open. Look for #");
                try {
                    socket.close();
                    Log.v(TAG,"#THIS CALL SHOULD BE MADE AFTER REACHED TIMEOUT AND SOCKET NOT OPEN");
                } catch (IOException e) {
                    Log.v(TAG,"Closing the socket connection fail--", e);
                }
            }else{
                Log.v(TAG, "Connected or Failed Before Timeout Thread Hit");
            }
        }

        public void setSocketConnected(){
            didSocketConnect = true;
        }

        public void setSocketFailed(){
            socketConnectFailed= true;
        }
    }
Run Code Online (Sandbox Code Playgroud)

当我调用close()时,它也会无限期地阻塞,并且connect()调用永远不会抛出IOException,尽管有BluetoothSocket.close()文档.使它工作的最佳方法是什么,以便connect()和close()不会无限期地阻塞?

注意:我正在为此项目使用Android 2.2.

Jac*_*ack 2

BluetoothSocket.connect() - 来自文档

尝试连接到远程设备。该方法将阻塞,直到建立连接或连接失败。如果此方法返回且没有异常,则此套接字现在已连接。

为了让您对 BluetoothSocket.connect() 的调用退出阻塞,它需要建立连接。这是设计使然,如果您考虑一下,获取我们想要连接的蓝牙设备的地址,调用 .connect(),并阻塞直到其连接,这是有道理的。这就是为什么你需要单独的线程。

至于您调用 .close(),如果您解决了 .connect() 的问题,.close() 应该就位。

请阅读这个。它基本上表示您需要一个名为“连接”(.connect()) 和“已连接”(InputStream.read()) 的单独线程。这样你的 UI 就不会被阻塞。

示例(来自上面的链接)。ConnectThread 启动连接。ConnectedThread 管理连接(读/写数据等)。

private class ConnectThread extends Thread {
    private final BluetoothSocket mmSocket;
    private final BluetoothDevice mmDevice;

    public ConnectThread(BluetoothDevice device) {
        // Use a temporary object that is later assigned to mmSocket,
        // because mmSocket is final
        BluetoothSocket tmp = null;
        mmDevice = device;

        // Get a BluetoothSocket to connect with the given BluetoothDevice
        try {
            // MY_UUID is the app's UUID string, also used by the server code
            tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
        } catch (IOException e) { }
        mmSocket = tmp;
    }

    public void run() {
        // Cancel discovery because it will slow down the connection
        mBluetoothAdapter.cancelDiscovery();

        try {
            // Connect the device through the socket. This will block
            // until it succeeds or throws an exception
            mmSocket.connect();
        } catch (IOException connectException) {
            // Unable to connect; close the socket and get out
            try {
                mmSocket.close();
            } catch (IOException closeException) { }
            return;
        }

        // Do work to manage the connection (in a separate thread)
        manageConnectedSocket(mmSocket);
    }

    /** Will cancel an in-progress connection, and close the socket */
    public void cancel() {
        try {
            mmSocket.close();
        } catch (IOException e) { }
    }
}


private class ConnectedThread extends Thread {
    private final BluetoothSocket mmSocket;
    private final InputStream mmInStream;
    private final OutputStream mmOutStream;

    public ConnectedThread(BluetoothSocket socket) {
        mmSocket = socket;
        InputStream tmpIn = null;
        OutputStream tmpOut = null;

        // Get the input and output streams, using temp objects because
        // member streams are final
        try {
            tmpIn = socket.getInputStream();
            tmpOut = socket.getOutputStream();
        } catch (IOException e) { }

        mmInStream = tmpIn;
        mmOutStream = tmpOut;
    }

    public void run() {
        byte[] buffer = new byte[1024];  // buffer store for the stream
        int bytes; // bytes returned from read()

        // Keep listening to the InputStream until an exception occurs
        while (true) {
            try {
                // Read from the InputStream
                bytes = mmInStream.read(buffer);
                // Send the obtained bytes to the UI Activity
                mHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer)
                        .sendToTarget();
            } catch (IOException e) {
                break;
            }
        }
    }

    /* Call this from the main Activity to send data to the remote device */
    public void write(byte[] bytes) {
        try {
            mmOutStream.write(bytes);
        } catch (IOException e) { }
    }

    /* Call this from the main Activity to shutdown the connection */
    public void cancel() {
        try {
            mmSocket.close();
        } catch (IOException e) { }
    }
}
Run Code Online (Sandbox Code Playgroud)