.connect()之后如何防止Android蓝牙RFCOMM连接立即死亡?
这个问题已经解决了! 非常感谢Brad,Denis和junkie! 你是英雄! 🙂
这是工作代码。 它连接到Zeemote并从中读取数据。
=====代码=====
公共类ZeeTest扩展活动{
@覆盖
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
的setContentView(R.layout.main);
尝试{
for(int i = 0; i <3; i ++){
testing();
}
catch(Exception e){
e.printStackTrace();
}
}
private boolean connected = false;
私人BluetoothSocket袜子;
private InputStream in;
公共无效testing()抛出exception{
如果(连接){
返回;
}
BluetoothDevice zee = BluetoothAdapter.getDefaultAdapter()。
getRemoteDevice( “00:1C:4D:02:A6:55”);
方法m = zee.getClass()。getMethod(“createRfcommSocket”,
new Class [] {int.class});
sock =(BluetoothSocket)m.invoke(zee,Integer.valueOf(1));
Log.d(“ZeeTest”,“++++连接”);
sock.connect();
Log.d(“ZeeTest”,“++++连接”);
in = sock.getInputStream();
byte [] buffer = new byte [50];
int read = 0;
Log.d(“ZeeTest”,“++++ Listening ...”);
尝试{
while(true){
read = in.read(buffer);
connected = true;
StringBuilder buf = new StringBuilder();
for(int i = 0; i <read; i ++){
int b = buffer [i]&0xff;
如果(b <0x10){
buf.append( “0”);
}
buf.append(Integer.toHexString(b))。append(“”);
}
Log.d(“ZeeTest”,“++++ Read”+ read +“bytes:”+ buf.toString());
}
catch(IOException e){}
Log.d(“ZeeTest”,“++++ Done:test()”);
}
@覆盖
public void onDestroy(){
尝试{
if(in!= null){
附寄();
}
if(sock!= null){
sock.close();
}
catch(IOException e){
e.printStackTrace();
}
super.onDestroy();
}
}
=====原始问题=====
我试图连接到运行2.0.1固件的Moto Droid的Zeemote( http://zeemote.com/ )游戏控制器。 下面的testing应用程序连接到设备(LED闪烁),但之后立即断开连接。
我正在粘贴下面的两个testing应用程序:一个实际上试图从inputstream中读取,另一个只是坐在那里,等待设备在5秒后断开连接。 是的,我有第三版:)首先等待ACL_CONNECTED,然后打开套接字,但没有什么新的行为。
一些背景信息:我可以从我的笔记本电脑连接到Zeemote使用bluez工具(日志附加以及)完美罚款。 我确定Droid能够和Zeemote交谈,因为市场上的“Game Pro”可以正常工作(但是它是一个驱动程序/服务,所以也许它使用低级的API)。
我注意到,'adb bugreport'不报告Zeemote的UUID和RFCOMM频道,而对于所有其他设备(包括Moto HS815耳机,另一个“sdp浏览器”不报告的哑设备)。 此外,当设备启动时,Zeemote的优先级为0(其他优先级为100+)。
我在这里感到非常茫然,我为此付出了太多时间,因此我想尽一切办法来帮助他们(即使你不知道答案:))
谢谢,马克斯
testing申请号1
这个应用程序试图从设备上实际读取。
=====代码=====
公共类ZeeTest扩展活动{
@覆盖
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
的setContentView(R.layout.main);
尝试{
testing();
catch(IOException e){
e.printStackTrace();
}
}
私人BluetoothSocket袜子;
private InputStream in;
公共无效testing()抛出IOException {
BluetoothDevice zee = BluetoothAdapter.getDefaultAdapter()。
getRemoteDevice( “00:1C:4D:02:A6:55”);
sock = zee.createRfcommSocketToServiceRecord(
UUID.fromString( “8e1f0cf7-508f-4875-b62c-fbb67fd34812”));
Log.d(“ZeeTest”,“++++连接”);
sock.connect();
Log.d(“ZeeTest”,“++++连接”);
in = sock.getInputStream();
byte [] buffer = new byte [1];
int bytes = 0;
int x = 0;
Log.d(“ZeeTest”,“++++ Listening ...”);
而(x <2){
X ++;
尝试{
bytes = in.read(buffer);
Log.d(“ZeeTest”,“++++ Read”+ bytes +“bytes”);
catch(IOException e){
e.printStackTrace();
尝试{Thread.sleep(100); catch(InterruptedException ie){}
}
}
Log.d(“ZeeTest”,“++++ Done:test()”);
}
@覆盖
public void onDestroy(){
尝试{
if(in!= null){
附寄();
}
if(sock!= null){
sock.close();
}
catch(IOException e){
e.printStackTrace();
}
super.onDestroy();
}
}
=====日志=====
04-19 22:27:01.147:DEBUG / ZeeTest(8619):++++连接 04-19 22:27:04.085:INFO / usbd(1062):process_usb_uevent_message():buffer = add @ / devices / virtual / bluetooth / hci0 / hci0:1 04-19 22:27:04.085:INFO / usbd(1062):main():call select(...) 04-19 22:27:04.327:ERROR / BluetoothEventLoop.cpp(4029):event_filter:从/ org / bluez / 4121 / hci0 / dev_00_1C_4D_02_A6_55接收到的信号org.bluez.Device:PropertyChanged 04-19 22:27:04.491:VERBOSE / BluetoothEventRedirector(7499):收到android.bleutooth.device.action.UUID 04-19 22:27:04.905:DEBUG / ZeeTest(8619):++++连接 04-19 22:27:04.905:DEBUG / ZeeTest(8619):++++ Listening ... 04-19 22:27:05.538:WARN / System.err(8619):java.io.IOException:软件导致连接中止 04-19 22:27:05.600:WARN / System.err(8619):在android.bluetooth.BluetoothSocket.readNative(本地方法) ... 04-19 22:27:05.717:WARN / System.err(8619):java.io.IOException:软件导致连接中止 04-19 22:27:05.717:警告/ System.err(8619):在android.bluetooth.BluetoothSocket.readNative(本地方法) ... 04-19 22:27:05.819:DEBUG / ZeeTest(8619):++++完成:test() 04-19 22:27:07.155:VERBOSE / BluetoothEventRedirector(7499):收到android.bleutooth.device.action.UUID 04-19 22:27:09.077:INFO / usbd(1062):process_usb_uevent_message():buffer = remove @ / devices / virtual / bluetooth / hci0 / hci0:1 04-19 22:27:09.085:INFO / usbd(1062):main():call select(...) 04-19 22:27:09.139:ERROR / BluetoothEventLoop.cpp(4029):event_filter:从/ org / bluez / 4121 / hci0 / dev_00_1C_4D_02_A6_55接收到信号org.bluez.Device:PropertyChanged
testing申请2号
此testing连接并等待 – 用于显示自动断开连接问题。
=====代码=====
公共类ZeeTest扩展活动{
@覆盖
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
的setContentView(R.layout.main);
getApplicationContext()。registerReceiver(接收器,
新的IntentFilter(BluetoothDevice.ACTION_ACL_CONNECTED));
getApplicationContext()。registerReceiver(接收器,
新的IntentFilter(BluetoothDevice.ACTION_ACL_DISCONNECTED));
尝试{
BluetoothDevice zee = BluetoothAdapter.getDefaultAdapter()。
getRemoteDevice( “00:1C:4D:02:A6:55”);
sock = zee.createRfcommSocketToServiceRecord(
UUID.fromString( “8e1f0cf7-508f-4875-b62c-fbb67fd34812”));
Log.d(“ZeeTest”,“++++连接”);
sock.connect();
Log.d(“ZeeTest”,“++++连接”);
catch(IOException e){
e.printStackTrace();
}
}
私人静态最终LogBroadcastReceiver receiver = new LogBroadcastReceiver();
公共静态类LogBroadcastReceiver扩展BroadcastReceiver {
@覆盖
public void onReceive(Context context,Intent intent){
Log.d(“ZeeReceiver”,intent.toString());
Bundle extras = intent.getExtras();
for(String k:extras.keySet()){
Log.d(“ZeeReceiver”,“Extra:”+ extras.get(k).toString());
}
}
}
私人BluetoothSocket袜子;
@覆盖
public void onDestroy(){
。getApplicationContext()unregisterReceiver(接收机);
if(sock!= null){
尝试{
sock.close();
catch(IOException e){
e.printStackTrace();
}
}
super.onDestroy();
}
}
=====日志=====
04-19 22:06:34.944:DEBUG / ZeeTest(7986):++++连接
04-19 22:06:38.202:INFO / usbd(1062):process_usb_uevent_message():buffer = add @ / devices / virtual / bluetooth / hci0 / hci0:1
04-19 22:06:38.202:INFO / usbd(1062):main():call select(...)
04-19 22:06:38.217:ERROR / BluetoothEventLoop.cpp(4029):event_filter:从/ org / bluez / 4121 / hci0 / dev_00_1C_4D_02_A6_55接收到的信号org.bluez.Device:PropertyChanged
04-19 22:06:38.428:VERBOSE / BluetoothEventRedirector(7499):收到android.bleutooth.device.action.UUID
04-19 22:06:38.968:DEBUG / ZeeTest(7986):++++连接
04-19 22:06:39.061:DEBUG / ZeeReceiver(7986):Intent {act = android.bluetooth.device.action.ACL_CONNECTED(has extras)}
04-19 22:06:39.108:DEBUG / ZeeReceiver(7986):Extra:00:1C:4D:02:A6:55
04-19 22:06:39.538:INFO / ActivityManager(4029):显示的活动zee.test / .ZeeTest:5178毫秒(总计5178毫秒)
04-19 22:06:41.014:VERBOSE / BluetoothEventRedirector(7499):收到android.bleutooth.device.action.UUID
04-19 22:06:43.038:INFO / usbd(1062):process_usb_uevent_message():buffer = remove @ / devices / virtual / bluetooth / hci0 / hci0:1
04-19 22:06:43.038:INFO / usbd(1062):main():call select(...)
04-19 22:06:43.069:ERROR / BluetoothEventLoop.cpp(4029):event_filter:从/ org / bluez / 4121 / hci0 / dev_00_1C_4D_02_A6_55接收到的信号org.bluez.Device:PropertyChanged
04-19 22:06:43.124:DEBUG / ZeeReceiver(7986):Intent {act = android.bluetooth.device.action.ACL_DISCONNECTED(has extras)}
04-19 22:06:43.124:DEBUG / ZeeReceiver(7986):Extra:00:1C:4D:02:A6:55
系统日志
=====terminal日志=====
$ sdptool浏览
查询 ...
浏览00:1C:4D:02:A6:55 ...
$ sdptoollogging00:1C:4D:02:A6:55
服务名称:Zeemote
服务RecHandle:0x10015
服务类别ID列表:
UUID 128:8e1f0cf7-508f-4875-b62c-fbb67fd34812
协议描述符列表:
“L2CAP”(0x0100)
“RFCOMM”(0x0003)
频道:1
语言基础列表:
code_ISO639:0x656e
编码:0x6a
base_offset:0x100
$ rfcomm connect / dev / tty10 00:1C:4D:02:A6:55
通道1上的/ dev / rfcomm0连接到00:1C:4D:02:A6:55
按CTRL-C进行挂机
#rfcomm show / dev / tty10
rfcomm0:00:1F:3A:E4:C8:40 - > 00:1C:4D:02:A6:55通道1已连接[重新使用dlc release-on-hup tty-attached]
#cat / dev / tty10
(这里没有什么)
#hcidump
HCI嗅探器 - 蓝牙数据包分析器版本1.42
设备:hci0 snap_len:1028filter:0xffffffff
<HCI命令:创build连接(0x01 | 0x0005)plen 13
> HCI事件:命令状态(0x0f)plen 4
> HCI事件:连接完成(0x03)plen 11
<HCI命令:读取远程支持的function(0x01 | 0x001b)plen 2
> HCI事件:读取远程支持的function(0x0b)plen 11
<ACL数据:处理11个标志0x02 dlen 10
L2CAP:信息请求:types2
> HCI事件:命令状态(0x0f)plen 4
> HCI事件:页面扫描重复模式更改(0x20)plen 7
> HCI事件:最大插槽更改(0x1b)plen 3
<HCI命令:远程名称请求(0x01 | 0x0019)plen 10
> HCI事件:命令状态(0x0f)plen 4
> ACL数据:处理11个标志0x02 dlen 16
L2CAP:信息rsp:types2结果0
扩展function掩膜0x0000
ACL数据:handle 11 flags 0x02 dlen 12
L2CAP(s):连接req:psm 3 scid 0x0040
> HCI事件:完成的数据包数量(0x13)plen 5
> ACL数据:处理11个标志0x02 dlen 16
L2CAP(s):连接rsp:dcid 0x04fb scid 0x0040结果1状态2
Connection pending - 授权等待中
> HCI事件:远程名称请求完成(0x07)plen 255
> ACL数据:处理11个标志0x02 dlen 16
L2CAP(s):连接rsp:dcid 0x04fb scid 0x0040结果0状态0
连接成功
<ACL数据:处理11个标志0x02 dlen 16
L2CAP(s):configuration请求:dcid 0x04fb标志0x00 clen 4
MTU 1013
(事件使用蓝色正确接收)
===== adb bugreport =====的一部分
- 已知设备 -
00:19:A1:2D:16:EA绑定(0)LG U830
00001105-0000-1000-8000-00805f9b34fb RFCOMM频道= 17
00:1C:4D:02:A6:55 bonded(0)Zeemote JS1
00:0B:2E:6E:6F:00保税(0)摩托罗拉HS815
00001108-0000-1000-8000-00805f9b34fb RFCOMM通道= 1
0000111e-0000-1000-8000-00805f9b34fb RFCOMM通道= 2
00:1F:3A:E4:C8:40 bonded(0)BRCM BT4X
00001105-0000-1000-8000-00805f9b34fb RFCOMM频道= 9
00:18:42:EC:E2:99结合(0)N95
00001105-0000-1000-8000-00805f9b34fb RFCOMM频道= 9
=====从开机日志摘录=====
04-18 21:55:10.382:VERBOSE / BluetoothEventRedirector(1985):收到android.bluetooth.adapter.action.STATE_CHANGED 04-18 21:55:10.421:DEBUG / BT HSHFP(1237):加载优先00:19:A1:2D:16:EA = 100 04-18 21:55:10.428:DEBUG / BT HSHFP(1237):加载优先00:1C:4D:02:A6:55 = 0 04-18 21:55:10.444:DEBUG / BT HSHFP(1237):加载优先00:0B:2E:6E:6F:00 = 101 04-18 21:55:10.749:DEBUG / BT HSHFP(1237):加载优先00:1F:3A:E4:C8:40 = 100 04-18 21:55:10.780:DEBUG / BT HSHFP(1237):加载优先00:18:42:EC:E2:99 = 100
尝试更改您的代码以创buildRfcommSocket:
sock = zee.createRfcommSocketToServiceRecord( UUID.fromString("8e1f0cf7-508f-4875-b62c-fbb67fd34812"));
对于这个代码:
Method m = zee.getClass().getMethod("createRfcommSocket", new Class[] { int.class }); sock = (BluetoothSocket) m.invoke(device, 1);
也可以尝试在m.invoke(device,1)中的范围1-3中更改参数值。 当连接将被连接,但当你尝试阅读时中止,再次调用一些循环你的方法testing()。 很简单:
for(int i=0;i<3;i++){ if(!testDone) test(); }
我合并的代码,我写的代码从[android-beginners]回复:串行蓝牙通过XCaffeinated] 1和上面的post。
创build最简单的蓝牙程序。
此代码的主要补充是对connect()抛出的exception进行更好的处理。
search“@todo”以自定义您的需求。
我希望这可以节省一些时间!
package com.xxx; // @todo Change to your package. import java.io.IOException; 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; /** * This is the simplest bluetooth program. It sends one message to one bluetooth * device. The message and the bluetooth hardware id for the device are hard * coded. <br> * <br> * It does <b>not</b> receive any data. It does not do any thread processing. <br> * <br> * * This application will be useful to communicate with a bluetooth hardware * device such as a bar code reader, Lego Mindstorm, a PC with a com port * application, a PC with a terminal program with 'listening' to a com port, a * second android device with a terminal program such as <a href= * "http://www.tec-it.com/en/software/data-acquisition/getblue/android-smartphone/Default.aspx" * >GetBlue</a>. It is not a full android bluetooth application but more a proof * of concept that the bluetooth works. * * <br> * <br> * * This code should cut and paste into the <a * href="http://developer.android.com/resources/tutorials/hello-world.html> * 'HelloAndroid' example</a>. It does not use any screen io. * * Add to your Android Manifest.xml file: <uses-permission * android:name="android.permission.BLUETOOTH" /> <uses-permission * android:name="android.permission.BLUETOOTH_ADMIN" /> * * For a proper bluetooth example with threading and receiving data see: <a * href= * "http://developer.android.com/resources/samples/BluetoothChat/index.html" * >http://developer.android.com/resources/samples/BluetoothChat/index.html</a> * * @see <a * href="http://developer.android.com/guide/topics/wireless/bluetooth.html"> * http://developer.android.com/guide/topics/wireless/bluetooth.html</a> * */ public class BlueToothTesterActivity extends Activity { /** The BluetoothAdapter is the gateway to all bluetooth functions **/ protected BluetoothAdapter bluetoothAdapter = null; /** We will write our message to the socket **/ protected BluetoothSocket socket = null; /** The Bluetooth is an external device, which will receive our message **/ BluetoothDevice blueToothDevice = null; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // Grab the BlueToothAdapter. The first line of most bluetooth programs. bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); // if the BluetoothAdapter.getDefaultAdapter(); returns null then the // device does not have bluetooth hardware. Currently the emulator // does not support bluetooth so this will this condition will be true. // ie This code only runs on a hardware device an not on the emulator. if (bluetoothAdapter == null) { Log.e(this.toString(), "Bluetooth Not Available."); return; } // This will find the remote device given the bluetooth hardware // address. // @todo: Change the address to the your device address blueToothDevice = bluetoothAdapter.getRemoteDevice("00:00:00:00:00:00"); for (Integer port = 1; port <= 3; port++) { simpleComm(Integer.valueOf(port)); } } protected void simpleComm(Integer port) { // byte [] inputBytes = null; // The documents tell us to cancel the discovery process. bluetoothAdapter.cancelDiscovery(); Log.d(this.toString(), "Port = " + port); try { // This is a hack to access "createRfcommSocket which is does not // have public access in the current api. // Note: BlueToothDevice.createRfcommSocketToServiceRecord (UUID // uuid) does not work in this type of application. . Method m = blueToothDevice.getClass().getMethod( "createRfcommSocket", new Class[] { int.class }); socket = (BluetoothSocket) m.invoke(blueToothDevice, port); // debug check to ensure socket was set. assert (socket != null) : "Socket is Null"; // attempt to connect to device socket.connect(); try { Log.d(this.toString(), "************ CONNECTION SUCCEES! *************"); // Grab the outputStream. This stream will send bytes to the // external/second device. ie it will sent it out. // Note: this is a Java.io.OutputStream which is used in several // types of Java programs such as file io, so you may be // familiar with it. OutputStream outputStream = socket.getOutputStream(); // Create the String to send to the second device. // Most devices require a '\r' or '\n' or both at the end of the // string. // @todo set your message String message = "Data from Android and tester program!\r"; // Convert the message to bytes and blast it through the // bluetooth // to the second device. You may want to use: // public byte[] getBytes (Charset charset) for proper String to // byte conversion. outputStream.write(message.getBytes()); } finally { // close the socket and we are done. socket.close(); } // IOExcecption is thrown if connect fails. } catch (IOException ex) { Log.e(this.toString(), "IOException " + ex.getMessage()); // NoSuchMethodException IllegalAccessException // InvocationTargetException // are reflection exceptions. } catch (NoSuchMethodException ex) { Log.e(this.toString(), "NoSuchMethodException " + ex.getMessage()); } catch (IllegalAccessException ex) { Log.e(this.toString(), "IllegalAccessException " + ex.getMessage()); } catch (InvocationTargetException ex) { Log.e(this.toString(), "InvocationTargetException " + ex.getMessage()); } } }
如果我理解正确,您的应用程序无法从设备中看到任何数据?
一件小事:尝试你的UUID没有hiphens。 在我的RFCOMM应用程序中,我实际上将UUID定义为长整数常量。
另外,你的test()方法的写法让我相信test()正在build立连接,定义一个线程,告诉它开始并立即返回。 换句话说,你的线程正在从线程之外引用一个variables,这个线程是test()方法的一部分,但是当test()死亡时,它的variables也是如此。
总之,尝试在线程之外进行testing,并首先在那里工作。 一个简单的方法就是使用Thread.run()而不是thread.start()。 .run()在前台运行(因此阻塞了test(),所以在线程完成之前它不会返回)。
对于更长期的解决scheme,您可能希望将您的蓝牙variables定义为gloibal /成员variables,以便它们不会超出范围,并始终可用于您的线程。
尝试众所周知的UUID:00001101-0000-1000-8000-00805F9B34FB
上面的代码不能在Samsung Galaxy Tab 2上使用4.0.4。 BTSocket.connect总是发射蓝牙配对对话,然后失败,即使正确的引脚input。 从“createRfcommSocket”更改为“createInsecureRfcommSocket”解决了这个问题。 希望这会有所帮助,我在这个问题上挣扎了3个多小时。