Bluetooth на Android: мой Socket.connect () блокируется навсегда, а Socket.close не разблокируется - PullRequest
7 голосов
/ 23 сентября 2011

Я какое-то время работал над приложением Bluetooth для Android, и я только что обнаружил эту проблему. Когда я преформирую mySocket.connect(); в своем классе обслуживания Bluetooth, он иногда блокируется на неопределенный срок. Я прочитал документацию для 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 Ответ

2 голосов
/ 23 сентября 2011

BluetoothSocket.connect () - Из документации :

Попытка подключения к удаленному устройству.Этот метод будет блокироваться до тех пор, пока не будет установлено соединение или соединение не будет установлено.Если этот метод возвращает без исключения, то этот сокет теперь подключен.

Чтобы ваш вызов BluetoothSocket.connect () мог выйти из блокировки, необходимо установить соединение.Это сделано специально, и это имеет смысл, если вы подумаете об этом, получите адрес устройства Bluetooth, к которому мы хотим подключиться, вызовем .connect () и заблокируем до его подключения.Вот почему вам нужны отдельные потоки.

Насколько вы вызываете .close (), если вы решаете проблемы с .connect (), .close () должен встать на свои места.

Пожалуйста, прочитайте это .В основном это говорит о том, что вам нужен отдельный поток, называемый «подключением» (.connect ()) и «подключенным» (InputStream.read ()).Таким образом, ваш пользовательский интерфейс не будет заблокирован.

Пример (по ссылке выше).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) { }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...