43

我正在开发一个程序,在该程序中,我必须从 Android 手机作为客户端连接到蓝牙医疗传感器。我使用的是官方的蓝牙 API,在连接过程中没有问题(SPP 配置文件),但是当我结束套接字时,传感器仍然连接到我的手机(虽然我已经关闭了连接)。

有什么方法可以断开蓝牙连接?我认为有一个名为 ACTION_ACL_CONNECTED 的意图,它可以做到这一点。谁能解释我如何使用它?

提前致谢。

已编辑:这是代码,如果有人需要更多信息,它是 Nonin 4100 医疗传感器。

Set<BluetoothDevice> pairedDevices = Activa.myBluetoothAdapter.getBondedDevices();
        // If there are paired devices
        if (pairedDevices.size() > 0) {
            // Loop through paired devices
            for (BluetoothDevice device : pairedDevices) {
                // Add the name and address to an array adapter to show in a ListView
                String name = device.getName();
                if (name.contains("Nonin")) {
                    try {
                        found = true;
//                      socket = device.createRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
//                      handler.sendEmptyMessage(5);
//                      Activa.myBluetoothAdapter.cancelDiscovery();
//                      socket.connect();
                        BluetoothDevice hxm = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(device.getAddress());
                        Method m;
                        try {
                            m = hxm.getClass().getMethod("createRfcommSocket", new Class[]{int.class});
                            socket = (BluetoothSocket)m.invoke(hxm, Integer.valueOf(1));
                            handler.sendEmptyMessage(5);
                            socket.connect();
                        } catch (Exception e) {
                            handler.sendEmptyMessage(7);
                            e.printStackTrace();
                            break;
                        }
                        handler.sendEmptyMessage(6);
                        InputStream in = socket.getInputStream();
                        OutputStream out = socket.getOutputStream();
                        byte[] retrieve = { 0x44, 0x31};
                        out.write(retrieve);
                        byte [] ack = new byte [1];
                        in.read(ack);
                        if (ack[0] == 0x15) {
                            cancelMeasurement();
                            return;
                        }
                        byte [] data = new byte [3];
                        long timeStart = System.currentTimeMillis();
                        this.timePassed = System.currentTimeMillis() - timeStart;
                        while ((this.timePassed < (this.time))&&(this.finished)) {
                            try {
                                in.read(data);
                                processData(data);
                                Thread.sleep(1000);
                                this.timePassed = System.currentTimeMillis() - timeStart;
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }
                        in.close();
                        out.close();
                        socket.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
}
4

6 回答 6

72

请记住先关闭输入/输出流,然后关闭套接字。

通过关闭流,您可以启动断开连接过程。关闭套接字后,连接应该完全断开。

如果您在流之前关闭套接字,您可能会绕过某些关闭步骤,例如(正确)关闭物理层连接。

这是我在断开连接时使用的方法。

/**
 * Reset input and output streams and make sure socket is closed. 
 * This method will be used during shutdown() to ensure that the connection is properly closed during a shutdown.  
 * @return
 */
private void resetConnection() {
        if (mBTInputStream != null) {
                try {mBTInputStream.close();} catch (Exception e) {}
                mBTInputStream = null;
        }

        if (mBTOutputStream != null) {
                try {mBTOutputStream.close();} catch (Exception e) {}
                mBTOutputStream = null;
        }

        if (mBTSocket != null) {
                try {mBTSocket.close();} catch (Exception e) {}
                mBTSocket = null;
        }

}

编辑:为 connect() 添加代码:

// bluetooth adapter which provides access to bluetooth functionality. 
BluetoothAdapter        mBTAdapter      = null;
// socket represents the open connection.
BluetoothSocket         mBTSocket   = null;
// device represents the peer
BluetoothDevice         mBTDevice       = null; 

// streams
InputStream           mBTInputStream  = null;
OutputStream          mBTOutputStream = null;

static final UUID UUID_RFCOMM_GENERIC = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");

/**
 * Try to establish a connection with the peer. 
 * This method runs synchronously and blocks for one or more seconds while it does its thing 
 * SO CALL IT FROM A NON-UI THREAD!
 * @return - returns true if the connection has been established and is ready for use. False otherwise. 
 */
private  boolean connect() {

        // Reset all streams and socket.
        resetConnection();

        // make sure peer is defined as a valid device based on their MAC. If not then do it. 
        if (mBTDevice == null) 
                mBTDevice = mBTAdapter.getRemoteDevice(mPeerMAC);

        // Make an RFCOMM binding. 
        try {mBTSocket = mBTDevice.createRfcommSocketToServiceRecord(UUID_RFCOMM_GENERIC);
        } catch (Exception e1) {
                msg ("connect(): Failed to bind to RFCOMM by UUID. msg=" + e1.getMessage());
                return false;
        }

        msg ("connect(): Trying to connect.");

        try {
                mBTSocket.connect();
        } catch (Exception e) {
                msg ("connect(): Exception thrown during connect: " + e.getMessage());
                return false;
        }

        msg ("connect(): CONNECTED!");

        try {
                mBTOutputStream = mBTSocket.getOutputStream();
                mBTInputStream  = mBTSocket.getInputStream();
        } catch (Exception e) {
                msg ("connect(): Error attaching i/o streams to socket. msg=" + e.getMessage());
                return false;
        }

        return true;
}
于 2010-06-14T18:26:44.537 回答
17

我发现,如果我在最近通过 OutputStream 进行通信后过早调用 socket.close(),则关闭失败并且我无法重新连接。我在调用 close() 之前添加了一个 Thread.sleep(1000) ,这似乎解决了它。

于 2014-03-31T18:23:02.650 回答
11

你好,

我见过完全相同的问题(HTC Desire)。尽管按书本关闭了套接字(正如布拉德建议的那样),但下一个 connect() 永远阻塞 - 直到由另一个线程 close() 结束。

我通过在连接之前总是调用 BluetoothAdapter.disable()/.enable() 来规避这个问题。可怕的,不友好的黑客,我知道......

我怀疑当前的一些 BT 问题是特定于制造商的,因为一些应用程序实现者似乎对 createRfcommSocketToServiceRecord() 感到满意,这在我的 HTC Desire(Android 2.1 更新 1)上肯定失败了。

我已经看到迹象(抱歉,没有参考资料)HTC Desire 的 BT 堆栈与 Nexus One 不同,尽管它们似乎是非常相似的设备......

BR每

(附加) 这是重现问题的一个非常简单的活动(没有我的禁用/启用“治愈”):

package com.care2wear.BtTest;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;

public class BtTestActivity extends Activity {
    private static final String TAG="BtTest";

    BluetoothAdapter mBtAdapter = null;
    BluetoothDevice mBtDev = null;
    BluetoothSocket mBtSocket = null;
    InputStream isBt;
    OutputStream osBt;  
    String mAddress = "00:18:E4:1C:A4:66";

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);


        init();

        connect();  // ok
        disconnect(); // ok
        connect(); // this invariably fails - blocked until BT is switched off by someone else, or the peer device turns off/goes out of range
        disconnect();
    }

    private void init() {
        Log.d(TAG, "initializing");
        mBtAdapter = BluetoothAdapter.getDefaultAdapter();
        mBtDev = mBtAdapter.getRemoteDevice(mAddress);
        Log.d(TAG, "initialized");
    }

    private void connect() {
        try {
            Log.d(TAG, "connecting");
            Method m = mBtDev.getClass().getMethod("createRfcommSocket", new Class[] { int.class });
            mBtSocket = (BluetoothSocket) m.invoke(mBtDev, 1);
            mBtSocket.connect();
            Log.d(TAG, "connected");
        } catch (SecurityException e) {
            Log.e(TAG, "SecEx", e);
        } catch (NoSuchMethodException e) {
            Log.e(TAG, "NsmEx", e);
        } catch (IllegalArgumentException e) {
            Log.e(TAG, "IArgEx", e);
        } catch (IllegalAccessException e) {
            Log.e(TAG, "IAccEx", e);
        } catch (InvocationTargetException e) {
            Log.e(TAG, "ItEx", e);
        } catch (IOException e) {
            Log.e(TAG, "IOEx", e);
        }

    }

    private void disconnect() {
        Log.d(TAG, "closing");

        if (isBt != null) {
            try {
                isBt.close();
            } catch (IOException e) {
                Log.e(TAG, "isBt IOE", e);              
            }
            isBt = null;
        }
        if (osBt != null) {
            try {
                osBt.close();
            } catch (IOException e) {
                Log.e(TAG, "osBt IOE", e);              
            }
            osBt = null;
        }
        if (mBtSocket != null) {
            try {
                mBtSocket.close();
            } catch (IOException e) {
                Log.e(TAG, "socket IOE", e);                
            }
            mBtSocket = null;
        }
        Log.d(TAG, "closed");       
    }
}

如果有人能发现我做错了,请随时发表评论:)

(加法2) 我想我现在可以工作了:

  1. 连接 RFCOMM(通过 SDP)的官方方法现在实际上似乎有效(HTC Desire,2.1 更新 1),我不得不移除并重新配对 BT 设备。去搞清楚..
  2. 如果我“太快”重新连接(退出应用程序,然后立即重新启动),重新连接可能仍会失败(服务发现失败)。猜猜连接还没有完全断开..
  3. 如果我总是不仅用 finish() 结束(最后一个)活动,而且用 Runtime.getRuntime().exit(0); 结束,它的效果会好很多。再上图...

如果有人能解释这一点,我会很高兴地学习。/每

(附加 3) 终于得到了我的 Desire 的 Froyo (2.2) 更新,据我所知,SPP 现在可以工作了 :) /Per

于 2010-07-18T08:22:19.397 回答
2

我正在开发一个连接到 BT 设备的应用程序。您的代码在我的 HTC Wildfire 中运行良好,但在三星 Galaxy I5700 中无法运行。两个操作系统都是2.1更新但是......

例外是“InvocationTargetException”

我唯一需要修改的是disconnect()。

private void disconnect() {
         if(Conectado){ 
            try {
                ***mBtSocket.close();***
                 texto.setText(texto.getText()+"\nDesconectado");
                 Conectado = false;
            } catch (IOException e1) {
                // TODO Auto-generated catch block
                texto.setText(texto.getText()+"\n"+e1.getMessage());
            } 
            catch (Exception e2) {
                // TODO Auto-generated catch block
                texto.setText(texto.getText()+"\n"+e2.getMessage());
            }    
         }
于 2010-09-15T20:18:23.700 回答
1

嘿,所以我一直在使用 Android 开发站点中的蓝牙聊天应用程序,它们stop()在 BluetoothChatService 类中提供了一个方法。所以我只是在我的主类中创建了它的一个实例,并从我的断开按钮中调用了停止函数。

这是我在主课上的称呼

// 聊天服务的成员对象

private BluetoothManager mChatService = null;
case R.id.disconnect:
        mChatService.stop();
break;

BluetoothChatService 中的 stop() 方法

private AcceptThread mAcceptThread;
private ConnectThread mConnectThread;
public synchronized void stop() 
{
    if (mConnectThread != null)
    {
        mConnectThread.cancel(); mConnectThread = null;
    }
    if (mConnectedThread != null) 
    {
        mConnectedThread.cancel(); mConnectedThread = null;
    }
    if (mAcceptThread != null) 
    {
        mAcceptThread.cancel(); mAcceptThread = null;
    }
}
于 2012-06-27T17:31:45.210 回答
0

我有同样的问题。这是蓝牙模块 CSR BC417 的问题,它在许多设备中作为具有 SPP 配置文件的串行到蓝牙适配器出现。使用另一个蓝牙模块 android 设备运行良好,并且蓝牙在套接字关闭后释放连接,但对于具有此 CSR 核心的设备则不行。在基于 CSR BC417 的 SPP 蓝牙转串口适配器和 Actisys 的蓝牙模块上进行了测试。两者都使用 Android 4.0 设备。我不知道为什么,但这是硬件之间的兼容性问题,尝试将串行适配器更改为具有不同核心的另一个。我以编程方式尝试找到解决方案,甚至禁用蓝牙,但这是不可能的,问题出在 CSR 模块上。

于 2014-03-24T20:38:49.080 回答