.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个多小时。