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

时间:2011-09-23 13:56:05

标签: android sockets 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;
        }
    }

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

注意:我在这个项目中使用Android 2.2。

1 个答案:

答案 0 :(得分:2)

BluetoothSocket.connect() - 来自documentation

  

尝试连接到远程设备。此方法将阻止直到a   建立连接或连接失败。如果此方法返回   没有例外,此套接字现已连接。

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

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

请阅读this。它基本上说你想要一个名为“连接”(.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) { }
    }
}