Android 上的蓝牙:我的 Socket.connect() 永远阻塞,而 Socket.close 不会解除阻塞 [英] Bluetooth On Android: my Socket.connect() Blocks forever, and Socket.close does not unblock

查看:15
本文介绍了Android 上的蓝牙:我的 Socket.connect() 永远阻塞,而 Socket.close 不会解除阻塞的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在为 android 开发蓝牙应用程序一段时间,我刚刚发现了这个问题.当我在我的蓝牙服务类中执行 mySocket.connect(); 时,它偶尔会无限期地阻塞.我阅读了 BluetoothSocket.close() 的文档,它说:

I have been working on a bluetooth app for android for awhile now and I just discovered this problem. When I preform mySocket.connect(); in my bluetooth service class it occasionally blocks indefinitely. I read the documentation for BluetoothSocket.close() and it says the following:

立即关闭这个socket,并释放所有关联的资源.

Immediately close this socket, and release all associated resources.

导致在其他线程中对该套接字的阻塞调用立即抛出一个 IOException.

Causes blocked calls on this socket in other threads to immediately throw an IOException.

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

However, this does not seem to work for me. Here is my code for setting a timer and then trying to connect.

//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() 不会无限期地阻塞?

When I call close(), it also blocks indefinitely and the connect() call never throws an IOException, despite BluetoothSocket.close() documentation. What is the best way to make it work so that the connect() and close() do not block indefinitely?

注意:我在这个项目中使用的是 Android 2.2.

NOTE: I am using Android 2.2 for this project.

推荐答案

BluetoothSocket.connect() - 来自 文档:

BluetoothSocket.connect() - From the documentation:

尝试连接到远程设备.此方法将阻塞,直到已建立连接或连接失败.如果这个方法返回无一例外,此套接字现在已连接.

Attempt to connect to a remote device. This method will block until a connection is made or the connection fails. If this method returns without an exception then this socket is now connected.

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

In order for your call to BluetoothSocket.connect() to quit blocking, it needs to make the connection. This is by design and it makes sense if you think about it, get the address of the Bluetooth device we want to connect to, call .connect(), and block until its connected. This is why you want separate threads.

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

As far as you calling .close(), if you work out the issues with .connect(), .close() should fall into place.

请阅读.它基本上是说你想要一个单独的线程,称为连接"(.connect())和连接"(InputStream.read()).这样您的用户界面就不会被屏蔽.

Please read this. It basically says you want a separate thread called "connecting" (.connect()) and "connected" (InputStream.read()). This way your UI will not be blocked.

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

Example (from the above link). ConnectThread initiates the connection. ConnectedThread manages the connection (reads/writes data, etc...).

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) { }
    }
}

这篇关于Android 上的蓝牙:我的 Socket.connect() 永远阻塞,而 Socket.close 不会解除阻塞的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆