Android(安卓)bluetooth 开发
Android bluetooth 开发 private void search() { BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); if (! adapter.isEnabled()) { adapter.enable(); } Intent enable = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE); enable.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 3600); // 3600为蓝牙设备可见时间 startActivity(enable); Intent searchIntent = new Intent( this, ComminuteActivity. class ); startActivity(searchIntent); } 首先,需要获得一个BluetoothAdapter,可以通过getDefaultAdapter()获得系统默认的蓝牙适配器,当然我们也可以自己指定,但这个真心没有必要,至少我是不需要的。然后我们检查手机的蓝牙是否打开,如果没有,通过enable()方法打开。接着我们再设置手机蓝牙设备的可见,可见时间可以自定义。 要想与任何蓝牙模块进行通信,首先得搜到该设备: private class BluetoothReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (BluetoothDevice.ACTION_FOUND.equals(action)) { BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); if (isLock(device)) { devices.add(device.getName()); } deviceList.add(device); } showDevices(); } }在这之前,我们得先调用一个方法: bluetoothAdapter.startDiscovery();startDiscovery()方法是一个异步方法,它会对其他蓝牙设备进行搜索,持续时间为12秒。搜索过程其实是在System Service中进行,我们可以通过cancelDiscovery()方法来停止这个搜索。在系统搜索蓝牙设备的过程中,系统可能会发送以下三个广播:ACTION_DISCOVERY_START(开始搜索),ACTION_DISCOVERY_FINISHED(搜索结束)和ACTION_FOUND(找到设备)。ACTION_FOUND这个才是我们想要的,这个Intent中包含两个extra fields:EXTRA_DEVICE和EXTRA_CLASS,包含的分别是BluetoothDevice和BluetoothClass,BluetoothDevice中的EXTRA_DEVICE就是我们搜索到的设备对象。 确认搜索到设备后,我们可以从得到的BluetoothDevice对象中获得设备的名称和地址。 在android中使用广播需要我们注册,这里也不例外: IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND); receiver = new BluetoothReceiver(); registerReceiver(receiver, filter);广播注册后需要我们撤销,这个可以放在这里进行: @Override protected void onDestroy() { unregisterReceiver(receiver); super .onDestroy(); } 这样在Activity结束的时候就会自动撤销该广播,而不需要我们手动执行。 搜索到该设备后,我们就要对该设备进行连接。 public void connect( final String message) { Thread thread = new Thread( new Runnable() { public void run() { BluetoothSocket tmp = null ; Method method; try { method = device.getClass().getMethod("createRfcommSocket", new Class[]{ int. class }); tmp = (BluetoothSocket) method.invoke(device, 1 ); } catch (Exception e) { setState(CONNECT_FAILED); Log.e("TAG" , e.toString()); } socket = tmp; try { socket.connect(); isConnect = true ; } catch (Exception e) { setState(CONNECT_FAILED); Log.e("TAG" , e.toString()); }连接设备之前需要UUID,所谓的UUID,就是用来进行配对的,全称是Universally Unique Identifier,是一个128位的字符串ID,用于进行唯一标识。网上的例子,包括谷歌的例子,它们的UUID都是说能用但是我用不了的,都会报出这样的错误: Service discovery failed 原因可能是作为唯一标识的UUID没有发挥作用,所以,我就利用反射的原理,让设备自己提供UUID。 这个错误在我们把手机既当做客户端有当做服务端的时候,同样也有可能出现,因为作为服务器的时候,我们需要的也是同一个UUID: mAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);作为客户端是这样的: device.createRfcommSocketToServiceRecord(MY_UUID);当两个UUID想同时建立Rfcomm的通道时,我们的选择都是在两个线程中分别实现,但是忽略了一件最重要的事情:同一个时间只能充当一个角色!所以,解决这个问题的方法就是在我们相连接的设备上也安装同样的应用程序,谁先发起连接谁就是客户端,但我这里是蓝牙模块啊!!怎么能安装我的应用程序呢!!解决办法就在下面的通信中。 连接设备之前还有一件事必须确保: bluetoothAdapter.cancelDiscovery(); 这是为了停掉搜索设备,否则连接可能会变得非常慢并且容易失败。 在使用Socket中,我注意到一个方法:isConnect(),它返回的是布尔值,但是根本就不需要使用到这个方法,Socket的连接如果没有报错,说明是已经连接上了。 在谷歌提供的例子中,我们可以看到谷歌的程序员的程序水平很高,一些好的编码习惯我们可以学习一下,像是在try..catch中才定义的变量,我们应该在try...catch之前声明一个临时变量,然后再在try...catch后赋值给我们真正要使用的变量。这种做法的好处就是:如果我们直接就是使用真正的变量,当出现异常的时候,该变量的使用就会出现问题,而且很难进行排查,如果是临时变量,我么可以通过检查变量的值来确定是否是赋值时出错。 谷歌的例子中最大的感想就是满满的异常检查,但也是因为这个,导致它的可读性不高。java的异常处理机制有时候对于代码的阅读真的不是一件舒服的事情,能避免就尽量避免。 如果连接没有问题,我们就可以和蓝牙模块进行通信: if (isConnect) { try { OutputStream outStream = socket.getOutputStream(); outStream.write(getHexBytes(message)); } catch (IOException e) { setState(WRITE_FAILED); Log.e("TAG" , e.toString()); } try { InputStream inputStream = socket.getInputStream(); int data; while ( true ) { try { data = inputStream.read(); Message msg = handler.obtainMessage(); msg.what = DATA; msg.arg1 = data; handler.sendMessage(msg); } catch (IOException e) { setState(READ_FAILED); Log.e("TAG" , e.toString()); break ; } } } catch (IOException e) { setState(WRITE_FAILED); Log.e("TAG" , e.toString()); } } if (socket != null ) { try { socket.close(); } catch (IOException e) { Log.e("TAG" , e.toString()); } } } }这里包括写入和读取,用法和基本的Socket是一样的,但是写入的时候,需要将字符串转化为16进制: private byte [] getHexBytes(String message) { int len = message.length() / 2 ; char[] chars = message.toCharArray(); String[] hexStr = new String[len]; byte[] bytes = new byte [len]; for ( int i = 0, j = 0; j < len; i += 2, j++ ) { hexStr[j] = "" + chars[i] + chars[i + 1 ]; bytes[j] = ( byte) Integer.parseInt(hexStr[j], 16 ); } return bytes; } 当然,这里只是将手机当做客户端,但是接收蓝牙模块发送过来的信息是没有必要特意创建服务端的,我们只要一个不断监听并读取对方消息的循环就行。 |
更多相关文章
- 将获取的html源代码格式化输出
- Android(安卓)连接.net WebService 工具类代码
- Android(安卓)加速器(accelerometer) 使用,判断设备移动
- imx515 开发板Android源代码编译过程
- Android判断网络是否连接
- Android(安卓)获得设备关联的帐号信息
- Android蓝牙的开启-搜索-关闭演示
- cocos2d-x获取设备信息
- Android(安卓)监控 网络连接状态