[转载]Android 通讯之蓝牙(-)API及通讯方法

   做者:BruceZhangandroid

   出处:http://blog.csdn.net/dlutbrucezhang/article/details/8955104web

                                                        

一般状况下,咱们对蓝牙的操做主要有:开启和关闭蓝牙、搜索周边设备、能被周边设备所发现、获取配对设备、蓝牙设备间的数据传输。编程

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

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

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

    它所包含的方法和BluetoothAdapter同样,再也不累述。网络

// 获取本地的蓝牙适配器实例  
             BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();  
             if(adapter!=null)  
             {  
                 if(!adapter.isEnabled())  
                 {  
                     //经过这个方法来请求打开咱们的蓝牙设备  
                     Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);  
                     startActivity(intent);  
                 }  
             }  
             else  
             {  
                 System.out.println("本地设备驱动异常!");  
             }

二、搜索周边设备

 

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

  实现一个本身的BroadCastReceiver类,并注册这个类。app

 private class BluetoothReciever extends BroadcastReceiver {  
   
         @Override  
         public void onReceive(Context context, Intent intent) {  
             // TODO Auto-generated method stub  
             String action = intent.getAction();  
             if (BluetoothDevice.ACTION_FOUND.equals(action)) {  
                 BluetoothDevice device = intent  
                         .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);  
                 System.out.println(device.getAddress());  
             }  
         }  
   
     }
IntentFilter intentFilter = new IntentFilter(BluetoothDevice.ACTION_FOUND);  
bluetoothReceive = new BluetoothReciever();  
registerReceiver(bluetoothReceive, intentFilter);

由于在注册一个Receiver后,程序并不知道该什么时候去回收它,因此须要咱们本身重写Activity类的onDestroy()方法。异步

protected void onDestroy() {  
         // TODO Auto-generated method stub  
         unregisterReceiver(bluetoothReceive);  
         super.onDestroy();  
     }

三、被周边设备所发现  

 

  若是须要用户确认操做,不须要获取底层蓝牙服务实例,能够经过一个Intent来传递ACTION_REQUEST_DISCOVERABLE参数, 这里经过startActivity来请求开启。socket

Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);  
 //50这个参数表明的是蓝牙设备能在多少秒内被发现              
 discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 50);  
             startActivity(discoverableIntent);

四、配对

  配对操做呢,通常都是发现设备后,由咱们人工来进行选择后系统自动去配对。咱们能够经过下面的方法来得到配对的设备:ide

//经过getBondedDevices方法来获取已经与本设备配对的设备  
                 Set<BluetoothDevice> device= adapter.getBondedDevices();  
                 if(device.size()>0)  
                 {  
                     for(Iterator iterator=device.iterator();iterator.hasNext();)  
                     {  
                         BluetoothDevice bluetoothDevice=(BluetoothDevice)iterator.next();  
                         System.out.println(bluetoothDevice.getAddress());  
                     }  
                 }

五、数据交换  

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

  在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监听。

 // Bluetooth的ServerSocket包装类  
     class BluetoothServer {  
         public BluetoothServer() throws IOException {  
         }  
   
         // 要创建一个ServerSocket对象,须要使用adapter.listenUsingRfcommWithServiceRecord方法  
 // UUID能够在网上去申请  
         private BluetoothServerSocket serverSocket = adapter.listenUsingRfcommWithServiceRecord("myServerSocket",  
                         UUID.fromString("84D1319C-FBAF-644C-901A-8F091F25AF04"));  
         BluetoothSocket socket = serverSocket.accept();  
   
         void m() throws IOException {  
             if (socket != null) {  
                 InputStream inputStream = socket.getInputStream();  
                 int read = -1;  
                 final byte[] bytes = new byte[1024];  
                 for (; (read = inputStream.read(bytes)) > -1;) {  
                     final int count = read;  
                     Thread _start = new Thread(new Runnable() {  
   
                         @Override  
                         public void run() {   
                             // TODO Auto-generated method stub  
                             StringBuilder sb = new StringBuilder();  
                             for (int i = 0; i < count; i++) {  
                                 if (i > 0) {  
                                     sb.append(' ');  
                                 }  
                                 String _s = Integer.toHexString(bytes[i] & 0xFF);  
                                 if (_s.length() < 2) {  
                                     sb.append('0');  
                                 }  
                                 sb.append(_s);  
                             }  
                             System.out.println(sb.toString());  
                         }  
                     });  
                     _start.start();  
                 }  
             }  
         }  
     }
  • 建立一个Client

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

class BluetoothClient {  
         BluetoothDevice device = null;  
   
         //经过构造函数来传入一个BluetoothDevice实例  
         public BluetoothClient(BluetoothDevice device) {  
             this.device = device;  
         }  
         BluetoothSocket socket = null;  
         void connetServer() throws IOException {  
             Thread _clientThread = new Thread(new Runnable() {  
                 public void run() {  
                     try {  
                         //经过BluetoothDevice实例的createRfcommSocketToServiceRecord方法能够返回一个带有UUID的BluetoothSocket实例  
                         socket = device.createRfcommSocketToServiceRecord(UUID.fromString("84D1319C-FBAF-644C-901A-8F091F25AF04"));  
                     } catch (IOException e1) {   
                         // TODO Auto-generated catch block  
                         e1.printStackTrace();  
                     }  
                     try {  
                         socket.connect();  
                     } catch (IOException e1) {   
                         // TODO Auto-generated catch block  
                         e1.printStackTrace();  
                     }  
                     if (socket != null) {  
                         try {  
                             socket.close();  
                         } catch (Exception e) {  
                             // TODO: handle exception  
                         }  
                     }  
                 }  
             });  
             _clientThread.start();  
         }  
     

getInputStream()——得到一个可读的流,该流在链接不成功的状况下依旧能够得到,可是对其操做的话就会报IOException的异常。须要从外部获取的数据都从该流中获取。

  getOutputStrem()——得到一个可写的流,该流在链接不成功的状况下依旧能够得到,可是对其操做的话就会报IOException的异常。须要往外部传输的数据均可以写到该流中传输出去。

  数据传输的大体流程以下:

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

  还要补充一点,因为蓝牙设备是系统设备,因此须要有相应的权限支持。在AndroidManifest.xml文件中添加上权限。

<uses-permission android:name="android.permission.BLUETOOTH"></uses-permission>  
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"></uses-permission>
相关文章
相关标签/搜索