断开 Android 中的蓝牙插座
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3031796/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Disconnect a bluetooth socket in Android
提问by user365610
I'm developing a program in which, from an Android Phone, I have to connect as a client to a Bluetooth medical sensor. I'm using the official Bluetooth API and no problem during connection (SPP profile), but when I end the socket, the sensor is still connected to my phone (although I have close the connection).
我正在开发一个程序,在该程序中,我必须从 Android 手机作为客户端连接到蓝牙医疗传感器。我使用的是官方蓝牙 API,连接期间没有问题(SPP 配置文件),但是当我结束套接字时,传感器仍然连接到我的手机(尽管我已经关闭了连接)。
Are there any way to make a Bluetooth disconnection? I think there is an intent called ACTION_ACL_CONNECTED, which does that. Can anyone explain me how to use this?
有没有办法让蓝牙断开连接?我认为有一个名为 ACTION_ACL_CONNECTED 的意图,它就是这样做的。谁能解释我如何使用它?
Thanks in advance.
提前致谢。
EDITED: Here is the code, if anyone needs additional info, it's a Nonin 4100 medical sensor.
编辑:这是代码,如果有人需要其他信息,它是一个 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();
}
}
}
}
}
回答by Brad Hein
Please remember to close your Input/output streams first, then close the socket.
请记住先关闭输入/输出流,然后关闭套接字。
By closing the streams, you kick off the disconnect process. After you close the socket, the connection should be fully broken down.
通过关闭流,您开始断开连接过程。关闭套接字后,连接应该完全断开。
If you close the socket before the streams, you may be bypassing certain shutdown steps, such as the (proper) closing of the physical layer connection.
如果在流之前关闭套接字,则可能会绕过某些关闭步骤,例如(正确)关闭物理层连接。
Here's the method I use when its time to breakdown the connection.
这是我在断开连接时使用的方法。
/**
* 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;
}
}
EDIT: Adding code for connect():
编辑:为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;
}
回答by djilk
I found that if I call socket.close() too soon after a recent communication via the OutputStream, then the close fails and I cannot reconnect. I added a Thread.sleep(1000) just prior to the call to close() and this seems to solve it.
我发现如果在最近通过 OutputStream 进行通信后过早调用 socket.close() ,则关闭失败并且我无法重新连接。我在调用 close() 之前添加了一个 Thread.sleep(1000) ,这似乎解决了它。
回答by Per Laursen
HI,
你好,
I've seen the exact same problem (HTC Desire). Despite closing the socket by the book (as Brad suggests), the next connect() blocks forever - until ended by close() by another thread.
我见过完全相同的问题(HTC Desire)。尽管按本书关闭了套接字(如 Brad 所建议的),但下一个 connect() 将永远阻塞 - 直到由另一个线程 close() 结束。
I circumvented the problem by always calling BluetoothAdapter.disable()/.enable() before connecting. Awful, unfriendly hack, I know...
我通过在连接之前总是调用 BluetoothAdapter.disable()/.enable() 来规避这个问题。可怕的,不友好的黑客,我知道......
I suspect that some of the present BT issues are manufacturer specific, as some app implementors seem to live happily with createRfcommSocketToServiceRecord(), which definitely fails on my HTC Desire (Android 2.1 update 1).
我怀疑目前的一些 BT 问题是特定于制造商的,因为一些应用程序实现者似乎对 createRfcommSocketToServiceRecord() 很满意,这在我的 HTC Desire(Android 2.1 更新 1)上肯定失败了。
I have seen indications (sorry, don't have references) that HTC Desire's BT stack differs from the Nexus One, although they seem to be very similar devices...
我已经看到迹象(抱歉,没有参考)表明 HTC Desire 的 BT 堆栈与 Nexus One 不同,尽管它们似乎是非常相似的设备......
BR Per
BR Per
(addition)Here's a very simple activity to reproduce the problem (without my disable/enable 'cure'):
(附加)这是重现问题的一个非常简单的活动(没有我的禁用/启用“治愈”):
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");
}
}
If anyone can spot if I'm doing it wrongly, feel free to comment :)
如果有人可以发现我是否做错了,请随时发表评论:)
(addition 2)I think I got it to work now:
(附加 2)我想我现在可以开始工作了:
- The official method of connecting RFCOMM (via SDP) now actually seems to work (HTC Desire, 2.1 update 1), BUTI had to remove and re-pair the BT device. Go figure..
- Reconnection may still fail (service discovery failure) if I reconnect 'too quickly' (quit app, then immediately restart). Guess the connection is not completely down yet..
- If I always end the (last) activity not only with finish(), but also with Runtime.getRuntime().exit(0);, it works a lot better. Go figure again...
- 连接 RFCOMM(通过 SDP)的官方方法现在似乎有效(HTC Desire,2.1 更新 1),但我不得不移除并重新配对 BT 设备。去搞清楚..
- 如果我“太快”重新连接(退出应用程序,然后立即重新启动),重新连接可能仍会失败(服务发现失败)。猜猜连接还没有完全断开..
- 如果我总是不仅用完成(),而且用 Runtime.getRuntime().exit(0); 结束(最后一个)活动,它的效果会好得多。再去算...
If anyone can explain this, I'll happily learn. /Per
如果有人可以解释这一点,我会很高兴地学习。/每
(addition 3)Finally got the Froyo (2.2) update for my Desire, and as far as I can see, SPP now works :) /Per
(附加 3)终于为我的 Desire 获得了 Froyo (2.2) 更新,据我所知,SPP 现在可以工作了 :) /Per
回答by user343464
I was developing an app that conects to a BT device. Your code works fine in my HTC Wildfire but with a Samsung Galaxy I5700 doen't work. Both os are 2.1 update but.....
我正在开发一个连接到 BT 设备的应用程序。您的代码在我的 HTC Wildfire 中运行良好,但在三星 Galaxy I5700 中不起作用。两个操作系统都是 2.1 更新,但是.....
The exception was 'InvocationTargetException'
异常是“InvocationTargetException”
The only thing I had to modify is the disconnect().
我唯一需要修改的是 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());
}
}
回答by Rafael Mancilla
Hey so I have been using the Bluetooth Chat application from The Android Development site and they provide a stop()
method in BluetoothChatService class. So I simply created an instance of it in my main class and and called the stop function from my disconnect button.
嘿,我一直在使用来自 Android 开发站点的蓝牙聊天应用程序,它们stop()
在 BluetoothChatService 类中提供了一个方法。所以我只是在我的主类中创建了一个它的实例,并从我的断开连接按钮调用了停止函数。
Here is how I call it in my main class
这是我在主课中的称呼
// Member object for the chat services
// 聊天服务的成员对象
private BluetoothManager mChatService = null;
case R.id.disconnect:
mChatService.stop();
break;
The stop() method in BluetoothChatService
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;
}
}
回答by Cacho Paraguay
I have the same Issue. This is the trouble with the Bluetooth Module CSR BC417, present in many devices as serial to bluetooth adapter with SPP profile. With another Bluetooth module android device works well, and the bluetooth release the conection after the socket is closed, but with devices with this CSR core not. Tested on SPP Bluetooth to Serial Adaptor based on CSR BC417, and Bluetooth module from Actisys. Both with Android 4.0 devices. I dont know why but is a compatibility issue between harwares, try to change the serial adaptor for another with a different Core. I tryout programatically to find a solution, even disabling a bluetooth, but is impossible, the trouble is originated on the CSR module.
我有同样的问题。这是蓝牙模块 CSR BC417 的问题,它作为具有 SPP 配置文件的串行蓝牙适配器出现在许多设备中。使用另一个蓝牙模块android设备运行良好,并且在套接字关闭后蓝牙释放连接,但具有此CSR核心的设备则不然。在基于 CSR BC417 的 SPP 蓝牙转串口适配器和 Actisys 的蓝牙模块上进行测试。均使用 Android 4.0 设备。我不知道为什么但这是硬件之间的兼容性问题,请尝试将串行适配器更改为具有不同核心的另一个。我以编程方式尝试找到解决方案,甚至禁用蓝牙,但不可能,问题出在 CSR 模块上。