【问题标题】:how to solve bluetooth connect() fails socket might be close如何解决蓝牙连接()失败套接字可能已关闭
【发布时间】:2019-11-14 08:11:19
【问题描述】:

我正在尝试制作一个与附近设备通信的应用。 我的应用由请求启用蓝牙并设置可发现模式的主要活动组成,因此它等待建立连接。

第二个活动负责查找附近的设备并进行配对。 配对后,一些配置消息会被交换,然后双方都会启动一个 ThirdActivity 来处理两个设备之间的通信。

我可以成功交换这些消息,但问题是我需要将 BluetoothService 对象(保存通信信息)传递给第三个活动。

因为我认为我不能实现 parcelable,所以我只是关闭了连接而不消除配对,然后通过创建一个新的 BluetoothService 对象但始终传递相同的 BluetoothDevice 在 thirdActivity 中重新创建 AcceptThread 和 ConnectThread。

从各种日志来看,AcceptThread 在accept() 上等待,而ConnectThread 失败,connect() 报告此错误。

W/System.err: java.io.IOException: read failed, socket might closed or timeout, read ret: -1
        at android.bluetooth.BluetoothSocket.readAll(BluetoothSocket.java:762)
        at android.bluetooth.BluetoothSocket.readInt(BluetoothSocket.java:776)
        at android.bluetooth.BluetoothSocket.connect(BluetoothSocket.java:399)
        at com.crossthebox.progetto.BluetoothService$ConnectThread.run(BluetoothService.java:118)

我能做什么?

这是蓝牙服务类

public class BluetoothService {
    private UUID myid = UUID.fromString("fa87c0d0-afac-11de-8a39-0800200c9a66");
    private static final String appName = "myapp";

    private static final int STATE_NONE = 0;       // we're doing nothing
    private static final int STATE_LISTEN = 1;     // now listening for incoming connections
    private static final int STATE_CONNECTING = 2; // now initiating an outgoing connection
    private static final int STATE_CONNECTED = 3;
    private static final int STATE_BUFFER_NOT_EMPTY = 4;
    private String message ="";

    private int mState;
    private final BluetoothAdapter mBluetoothAdapter;
    Context mContext;

    private AcceptThread mAcceptThread;

    private ConnectThread mConnectThread;
    private BluetoothDevice mDevice;
    private UUID deviceUUID;


    private ConnectedThread mConnectedThread;

    public BluetoothService(Context context) {
        mContext = context;
        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        mState = STATE_NONE;
    }

    private class AcceptThread extends Thread {

        private final BluetoothServerSocket bluetoothServerSocket;

        public AcceptThread(){
            BluetoothServerSocket tmp = null;

            try{
                tmp = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(appName, myid);
            }catch (IOException e){

            }
            bluetoothServerSocket = tmp;
            mState  = STATE_LISTEN;
        }

        public void run() {
            BluetoothSocket socket = null;

            try {
                socket = bluetoothServerSocket.accept();

            } catch (IOException e) {

            }
            if (socket != null) {
                mState = STATE_CONNECTING;
                connected(socket);
            }
        }

        public void cancel() {
            try {
                bluetoothServerSocket.close();
            } catch (IOException e) {
            }
        }
    }

    private class ConnectThread extends Thread {
        private BluetoothSocket mSocket;

        public ConnectThread(BluetoothDevice device, UUID uuid) {
            mDevice = device;
            deviceUUID = uuid;
        }

        public void run(){
            BluetoothSocket tmp = null;
            // Get a BluetoothSocket for a connection with the
            // given BluetoothDevice
            try {
               tmp = mDevice.createRfcommSocketToServiceRecord(deviceUUID);
            } catch (IOException e) {

            }
            mSocket = tmp;

            mBluetoothAdapter.cancelDiscovery();

            try {
                mSocket.connect(); //this throws exception for socket close ( but only the second time)
            } catch (IOException e) {
                // Close the socket
                try {
                    mSocket.close();
                } catch (IOException e1) {
                }
                e.printStackTrace();
            }
            connected(mSocket);
        }
        public void cancel() {
            try {
                mSocket.close();
            } catch (IOException e) {
            }

        }
    }

    public synchronized void start() {
        if (mConnectThread != null) {
            mConnectThread.cancel();
            mConnectThread = null;
        }
        if (mAcceptThread == null) {
            mAcceptThread = new AcceptThread();
            mAcceptThread.start();
        }
    }


    public void startClient(BluetoothDevice device,UUID uuid){
        mConnectThread = new ConnectThread(device, uuid);
        mConnectThread.start();
    }

    private class ConnectedThread extends Thread {
        private final BluetoothSocket mSocket;
        private final InputStream mInStream;
        private final OutputStream mOutStream;

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

            try {
                tmpIn = mSocket.getInputStream();
                tmpOut = mSocket.getOutputStream();
            } catch (IOException e) {
                e.printStackTrace();
            }

            mInStream = tmpIn;
            mOutStream = tmpOut;
        }

        public void run(){
            byte[] buffer = new byte[1024];

            int bytes; // bytes returned from read()

            // Keep listening to the InputStream until an exception occurs
            while (true) {
                // Read from the InputStream
                try {
                    bytes = mInStream.read(buffer);
                    if(bytes != 0) {
                        String incomingMessage = new String(buffer, 0, bytes);
                        message = incomingMessage;
                        System.out.println("HO LETTO " + message);
                        mState = STATE_BUFFER_NOT_EMPTY;
                    }
                } catch (IOException e) {
                    break;
                }
            }
        }

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

            }
        }

        //termina la connessione
        public void cancel() {
            try {
                mSocket.close();
            } catch (IOException e) { }
        }
    }

    private void connected(BluetoothSocket mSocket) {
        // Start the thread to manage the connection and perform transmissions
        mConnectedThread = new ConnectedThread(mSocket);
        mConnectedThread.start();
        mState = STATE_CONNECTED;

    }

    public void write(byte[] out) {
        // Create temporary object
        ConnectedThread r;
        // Synchronize a copy of the ConnectedThread
        synchronized (this) {
            if (mState != STATE_CONNECTED) {
                return;}
            r = mConnectedThread;
        }
        // Perform the write unsynchronized
        r.write(out);
    }

    public int getState(){

        return mState;
    }
    public String getMessage(){
        String tmp = null;
        if(!message.equals("")){
            tmp = message;
            message = "";
        }
        mState = STATE_CONNECTED;
        return tmp;
    }
    public void setState(int state){
        this.mState = state;
    }

    public void cancel(){
        if(mAcceptThread != null) {
            mAcceptThread.cancel();
            mAcceptThread = null;
        }
        if(mConnectThread != null) {
            mConnectThread.cancel();
            mConnectThread = null;
        }
        if(mConnectedThread != null) {
            mConnectedThread.cancel();
            mConnectedThread = null;
        }
    }
}

主活动

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_transition);
        /* * */

    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        /* * */
        if(requestCode == DISCOVER_REQUEST){
            if(resultCode ==  120){

                bluetoothService = new BluetoothService(this);
                bluetoothService.start();

                //after receiving some message correctly
                Intent thirdActivity = new Intent(this, com.project.ThirdActivity.class);
                bluetoothService.cancel();
                this.startActivity(thirdActivity);
                finish();
            }
            if(resultCode == RESULT_CANCELED){
                finish();
            }
        }
    }

}

SecondActivity 我取消连接的方式和 MainActivity 差不多。我在收到一些消息后关闭套接字,然后启动 ThirdActivity

第三个活动

if(mode == CLIENT){
    BluetoothDEvice bluetoothDevice = getIntent().getExtras().getParcelable("btdevice");
    bluetoothService.startClient(bluetoothDevice,myid);
}else //SERVER
    bluetoothService.start();

【问题讨论】:

    标签: android sockets bluetooth android-bluetooth


    【解决方案1】:

    可能的解决方案:

    1. 将选定的 MAC 地址从 Activity2 传递给 Activity3
    2. 在 Activity3 中启动蓝牙服务中的 ConnectThread。
    3. 使用 Handler 在服务和 Activity3 之间进行通信。
    4. 确保在套接字断开连接时关闭线程。

    一个精彩的例子在下面的链接中:

    https://github.com/googlesamples/android-BluetoothChat

    【讨论】:

    • 是的,我遵循了那个例子,但我无法理解处理程序的使用,是的,我将 bluetoothDevice 引用从 SecondActivity 传递给 ThirdActivity 实际上在 ThirdActivity 中我采取了额外的意图
    • 将 Handler 视为 ConnectedThread 和 Activity3 之间的信使。显然,您从 InputStream 读取数据并将其发送到 Activity3。所以在 Activity3 中创建一个处理程序实例并将其传递给服务。
    猜你喜欢
    • 2023-03-23
    • 2017-06-05
    • 1970-01-01
    • 1970-01-01
    • 2013-09-10
    • 1970-01-01
    相关资源
    最近更新 更多