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