Android 通信--蓝牙

来源:互联网 发布:51单片机串口程序 编辑:程序博客网 时间:2024/04/29 02:44

Android 通信--蓝牙

分类: Android 《Android网络编程》 45人阅读 评论(0) 收藏 举报
Android蓝牙服务器搜索行业数据

目录(?)[+]

通常情况下,我们对蓝牙的操作主要有:开启和关闭蓝牙、搜索周边设备、能被周边设备所发现、获取配对设备、蓝牙设备间的数据传输。

  1、打开蓝牙(当然首先要确保你的手机是有蓝牙设备的)

  蓝牙设备主要分为两部分,一部分为本地设备,另一部分为远程设备。

  • BluetoothAdapter——本地设备,对蓝牙操作首先就需要有一个BluetoothAdapter实例。常用的几个方法如下:
    •   cancelDiscovery()——取消本地蓝牙设备的搜索操作,如果本地设备正在进行搜索,那么调用该方法后将停止搜索操作。
    •   Disable()——关闭蓝牙设备。
    •   Enable()——打开蓝牙设备。相信大家都有过打开蓝牙的经历,一般情况下都会弹出一个窗口,说正在请求打开蓝牙设备,你是不是允许云云。
    •   getAddress()——获取蓝牙设备的MAC地址。
    •   GetDefaultAdapter()——获取本地的蓝牙设备
    •   getName()——获取本地蓝牙的名称
    •   getRemoteDevice(String address)——根据远程设备的MAC地址来获取远程设备
    •   startDiscovery()——蓝牙设备开始搜索周边设备
  • BuletoothDevice——远程设备。

    它所包含的方法和BluetoothAdapter一样,不再累述。

[java] view plaincopy
  1. <span style="background-color: rgb(255, 255, 255);"><span style="font-size:18px;"><strong>View Code   
  2.  // 获取本地的蓝牙适配器实例  
  3.              BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();  
  4.              if(adapter!=null)  
  5.              {  
  6.                  if(!adapter.isEnabled())  
  7.                  {  
  8.                      //通过这个方法来请求打开我们的蓝牙设备  
  9.                      Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);  
  10.                      startActivity(intent);  
  11.                  }  
  12.              }  
  13.              else  
  14.              {  
  15.                  System.out.println("本地设备驱动异常!");  
  16.              }</strong></span></span>  

2、搜索周边设备

  对于Android查找发现蓝牙设备使用BluetoothAdapter类的startDiscovery()方法就可以执行一个异步方式获取周边的蓝牙设备,因为是一个异步的方法所以我们不需要考虑线程被阻塞问题,整个过程大约需要12秒时间,这时我们可以注册一个 BroadcastReceiver 对象来接收查找到的蓝牙设备信息,我们通过Filter来过滤ACTION_FOUND这个 Intent动作以获取每个远程设备的详细信息,通过Intent字段EXTRA_DEVICE 和 EXTRA_CLASS可以获得包含了每个BluetoothDevice 对象和对象的该设备类型 BluetoothClass。

  实现一个自己的BroadCastReceiver类,并注册这个类。

[java] view plaincopy
  1. <span style="background-color: rgb(255, 255, 255);"><span style="font-size:18px;"><strong>View Code   
  2.      private class BluetoothReciever extends BroadcastReceiver {  
  3.    
  4.          @Override  
  5.          public void onReceive(Context context, Intent intent) {  
  6.              // TODO Auto-generated method stub  
  7.              String action = intent.getAction();  
  8.              if (BluetoothDevice.ACTION_FOUND.equals(action)) {  
  9.                  BluetoothDevice device = intent  
  10.                          .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);  
  11.                  System.out.println(device.getAddress());  
  12.              }  
  13.          }  
  14.    
  15.      }</strong></span></span>  

[java] view plaincopy
  1. <span style="background-color: rgb(255, 255, 255);"><span style="font-size:18px;"><strong>IntentFilter intentFilter = new IntentFilter(BluetoothDevice.ACTION_FOUND);  
  2. bluetoothReceive = new BluetoothReciever();  
  3. registerReceiver(bluetoothReceive, intentFilter);</strong></span></span>  

因为在注册一个Receiver后,程序并不知道该何时去回收它,所以需要我们自己重写Activity类的onDestroy()方法。

[java] view plaincopy
  1. <span style="background-color: rgb(255, 255, 255);"><span style="font-size:18px;"><strong>@Override  
  2.      protected void onDestroy() {  
  3.          // TODO Auto-generated method stub  
  4.          unregisterReceiver(bluetoothReceive);  
  5.          super.onDestroy();  
  6.      }</strong></span></span>  

3、被周边设备所发现  

  如果需要用户确认操作,不需要获取底层蓝牙服务实例,可以通过一个Intent来传递ACTION_REQUEST_DISCOVERABLE参数, 这里通过startActivity来请求开启。

[java] view plaincopy
  1. <span style="background-color: rgb(255, 255, 255);"><span style="font-size:18px;"><strong>Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);  
  2.  //50这个参数代表的是蓝牙设备能在多少秒内被发现              
  3.  discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 50);  
  4.              startActivity(discoverableIntent);</strong></span></span>  

4、配对

  配对操作呢,一般都是发现设备后,由我们人工来进行选择后系统自动去配对。我们可以通过下面的方法来获得配对的设备:

[java] view plaincopy
  1. <span style="background-color: rgb(255, 255, 255);"><span style="font-size:18px;"><strong>View Code   
  2.                  //通过getBondedDevices方法来获取已经与本设备配对的设备  
  3.                  Set<BluetoothDevice> device= adapter.getBondedDevices();  
  4.                  if(device.size()>0)  
  5.                  {  
  6.                      for(Iterator iterator=device.iterator();iterator.hasNext();)  
  7.                      {  
  8.                          BluetoothDevice bluetoothDevice=(BluetoothDevice)iterator.next();  
  9.                          System.out.println(bluetoothDevice.getAddress());  
  10.                      }  
  11.                  }</strong></span></span>  

5、数据交换  

  在看过前面的启动、发现/搜索、配对这些操作后,下面来说说数据传输的问题。

  在Android系统中,蓝牙设备间的数据传输问题和我们在PC上的网络编程颇为类似,有一端作为Server端监听Client端的连接请求,在二者建立了连接后,就可以使用普通的数据传输方式进行数据交换操作了。在这个过程中,我需要使用到BluetoothServerSocket和BluetoothSocket两个类来建立Server端和Client端,还需要使用到一些关于流(Stream)的知识。

  • BluetoothServerSocket——服务端(监听端、监听器、接受请求的一端)
    • Accept()——阻塞宿主线程,直至收到客户端请求。返回BluetoothSocket对象。由于这个
    • Accept(int timeout)——阻塞宿主线程,直至收到客户端请求或等待时间超过timeout。返回BluetoothSocket对象。
    • Close()——关闭BluetoothServerSocket监听器。

  可以看到,Accept方法是一个阻塞方法,所以在进行开发的时候,一般都需要用到多线程的知识。JAVA的多线程知识,可以在JAVA的JDK帮助文档中查看,就单纯的应用来说还是比较简单的。

  • BluetoothSocket——客户端(请求端)
    • Close()——关闭BluetoothSocket请求端。
    • Connect()——主动向服务端(监听端)发起连接请求。

  在了解了这两个类后,可以着手来建立我们自己的Server端和Client端了。

  如果一个设备需要和两个或多个设备连接时,就需要作为一个server来传输,服务器端套接字在接受(accepted) 一个客户发来的BluetoothSocket连接请求时作出相应的响应。服务器socket将监听进入的连接请求,一旦连接被接受,将产生一个BluetoothSocket。

  • 创建一个Server

  使用BluetoothAdapter类的listenUsingRfcommWithServiceRecord方法来新建一个ServerSocket。在listenUsingRfcommWithServiceRecord中有一个参数叫做UUID,UUID(Universally Unique Identifier)是一个128位的字符串ID,被用于唯一标识我们的蓝牙服务。你可以使用web上的任何一款UUID产生器为你的程序获取一个UUID,然后使用fromString(String)初始化一个UUID。

  使用ServerSocket实例的accept方法进行监听,当监听到带有我们初始化的UUID参数的连接请求后作出响应,连接成功后返回一个BluetoothSocket对象。连接完成后,调用close方法关闭该Socket监听。

[java] view plaincopy
  1. <span style="background-color: rgb(255, 255, 255);"><span style="font-size:18px;"><strong>View Code   
  2.      // Bluetooth的ServerSocket包装类  
  3.      class BluetoothServer {  
  4.          public BluetoothServer() throws IOException {  
  5.          }  
  6.    
  7.          // 要建立一个ServerSocket对象,需要使用adapter.listenUsingRfcommWithServiceRecord方法  
  8.  // UUID可以在网上去申请  
  9.          private BluetoothServerSocket serverSocket = adapter.listenUsingRfcommWithServiceRecord("myServerSocket",  
  10.                          UUID.fromString("84D1319C-FBAF-644C-901A-8F091F25AF04"));  
  11.          BluetoothSocket socket = serverSocket.accept();  
  12.    
  13.          void m() throws IOException {  
  14.              if (socket != null) {  
  15.                  InputStream inputStream = socket.getInputStream();  
  16.                  int read = -1;  
  17.                  final byte[] bytes = new byte[1024];  
  18.                  for (; (read = inputStream.read(bytes)) > -1;) {  
  19.                      final int count = read;  
  20.                      Thread _start = new Thread(new Runnable() {  
  21.    
  22.                          @Override  
  23.                          public void run() {   
  24.                              // TODO Auto-generated method stub  
  25.                              StringBuilder sb = new StringBuilder();  
  26.                              for (int i = 0; i < count; i++) {  
  27.                                  if (i > 0) {  
  28.                                      sb.append(' ');  
  29.                                  }  
  30.                                  String _s = Integer.toHexString(bytes[i] & 0xFF);  
  31.                                  if (_s.length() < 2) {  
  32.                                      sb.append('0');  
  33.                                  }  
  34.                                  sb.append(_s);  
  35.                              }  
  36.                              System.out.println(sb.toString());  
  37.                          }  
  38.                      });  
  39.                      _start.start();  
  40.                  }  
  41.              }  
  42.          }  
  43.      }</strong></span></span>  

  • 创建一个Client

  创建一个Client端,首先需要我们使用BluetoothDevice的实例的createRfcommSocketToServiceRecord方法来创建一个BluetoothSocket实例。在创建的时候,需要给createRfcommSocketToServiceRecord方法传入我们服务端的UUID值。然后使用BluetoothSocket实例的Connect方法对Server端进行连接请求,当连接成功后,Client端和Server端的传输通道就被打开。最后在连接完成后使用该实例的close方法来关闭这个连接。

[java] view plaincopy
  1. <span style="background-color: rgb(255, 255, 255);"><span style="font-size:18px;"><strong>View Code   
  2.  class BluetoothClient {  
  3.          BluetoothDevice device = null;  
  4.    
  5.          //通过构造函数来传入一个BluetoothDevice实例  
  6.          public BluetoothClient(BluetoothDevice device) {  
  7.              this.device = device;  
  8.          }  
  9.          BluetoothSocket socket = null;  
  10.          void connetServer() throws IOException {  
  11.              Thread _clientThread = new Thread(new Runnable() {  
  12.                  public void run() {  
  13.                      try {  
  14.                          //通过BluetoothDevice实例的createRfcommSocketToServiceRecord方法可以返回一个带有UUID的BluetoothSocket实例  
  15.                          socket = device.createRfcommSocketToServiceRecord(UUID.fromString("84D1319C-FBAF-644C-901A-8F091F25AF04"));  
  16.                      } catch (IOException e1) {   
  17.                          // TODO Auto-generated catch block  
  18.                          e1.printStackTrace();  
  19.                      }  
  20.                      try {  
  21.                          socket.connect();  
  22.                      } catch (IOException e1) {   
  23.                          // TODO Auto-generated catch block  
  24.                          e1.printStackTrace();  
  25.                      }  
  26.                      if (socket != null) {  
  27.                          try {  
  28.                              socket.close();  
  29.                          } catch (Exception e) {  
  30.                              // TODO: handle exception  
  31.                          }  
  32.                      }  
  33.                  }  
  34.              });  
  35.              _clientThread.start();  
  36.          }  
  37.      }</strong></span></span>  

getInputStream()——获得一个可读的流,该流在连接不成功的情况下依旧可以获得,但是对其操作的话就会报IOException的异常。需要从外部获取的数据都从该流中获取。

  getOutputStrem()——获得一个可写的流,该流在连接不成功的情况下依旧可以获得,但是对其操作的话就会报IOException的异常。需要往外部传输的数据都可以写到该流中传输出去。

  数据传输的大致流程如下:

    • 首先,分别通过getInputStream()和getOutputStream()获得管理数据传输的InputStream和OutputStream。
    • 然后,开辟一个线程专门用于数据的读或写。这是非常重要的,因为read(byte[])和write(byte[])方法都是阻塞调用。read(byte[])从输入流(InputStream)中读取数据。write(byte[])将数据写入到OutputStream流中去,这个方法一般不会阻塞,但当远程设备的中间缓冲区已满而对方没有及时地调用read(byte[])时将会一直阻塞。所以,新开辟的线程中的主循环将一直用于从InputStream中读取数据。

  还要补充一点,由于蓝牙设备是系统设备,所以需要有相应的权限支持。在AndroidManifest.xml文件中添加上权限。

[html] view plaincopy
  1. <span style="background-color: rgb(255, 255, 255);"><span style="font-size:18px;"><strong><uses-permission android:name="android.permission.BLUETOOTH"></uses-permission>  
  2. <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"></uses-permission></strong></span></span>  
原创粉丝点击