在Android中断开蓝牙插座

时间:2010-06-13 09:56:03

标签: android bluetooth disconnection

我正在开发一个程序,其中,从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();
                    }
                }
            }
        }
}

6 个答案:

答案 0 :(得分:59)

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

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

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

这是我在分解连接时使用的方法。

/**
 * 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;
}

答案 1 :(得分:13)

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

答案 2 :(得分:9)

HI,

我已经看到了完全相同的问题(HTC Desire)。 尽管本书关闭了套接字(正如Brad建议的那样),但下一个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), BUT 我必须移除并重新配对BT设备。去图..
  2. 如果我“太快”重新连接,则重新连接可能仍会失败(服务发现失败)(退出应用程序,然后立即重新启动)。猜猜连接还没完全停止..
  3. 如果我总是结束(最后)活动,不仅使用finish(),还使用Runtime.getRuntime()。exit(0);,它的效果会好很多。再来一次......
  4. 如果有人能够解释这一点,我会高兴地学习。 /每

    (补充3) 终于得到了我的欲望的Froyo(2.2)更新,据我所知,SPP现在可以工作:) /每

答案 3 :(得分: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());
            }    
         }

答案 4 :(得分:1)

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

以下是我在主课程中的称呼方式

//聊天服务的成员对象

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;
    }
}

答案 5 :(得分:0)

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