乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      Android 與BLE設(shè)備通訊

       杰出天下 2018-08-13

       

      一、基本介紹

      BLE全稱Bluetooth Low Energy即低功耗藍(lán)牙。

      Android 4.3(API Level 18)開(kāi)始引入核心功能并提供了相應(yīng)的 API, 應(yīng)用程序通過(guò)這些 API 掃描藍(lán)牙設(shè)備、查詢 services、讀寫(xiě)設(shè)備的 characteristics(屬性特征)等操作。

      Android BLE 使用的藍(lán)牙協(xié)議是 GATT 協(xié)議,有關(guān)該協(xié)議的詳細(xì)內(nèi)容可以參見(jiàn)官方文檔。

      Service

      一個(gè)低功耗藍(lán)牙設(shè)備可以定義許多 Service, Service 可以理解為一個(gè)功能的集合。設(shè)備中每一個(gè)不同的 Service 都有一個(gè) 128 bit 的 UUID 作為這個(gè) Service 的獨(dú)立標(biāo)志。藍(lán)牙核心規(guī)范制定了兩種不同的UUID,一種是基本的UUID,一種是代替基本UUID的16位UUID。所有的藍(lán)牙技術(shù)聯(lián)盟定義UUID共用了一個(gè)基本的UUID: 0x0000xxxx-0000-1000-8000-00805F9B34FB 為了進(jìn)一步簡(jiǎn)化基本UUID,每一個(gè)藍(lán)牙技術(shù)聯(lián)盟定義的屬性有一個(gè)唯一的16位UUID,以代替上面的基本UUID的'x’部分。例如,心率測(cè)量特性使用0X2A37作為它的16位UUID,因此它完整的128位UUID為: 0x00002A37-0000-1000-8000-00805F9B34FB

      Characteristic

      在 Service 下面,又包括了許多的獨(dú)立數(shù)據(jù)項(xiàng),我們把這些獨(dú)立的數(shù)據(jù)項(xiàng)稱作 Characteristic。同樣的,每一個(gè) Characteristic 也有一個(gè)唯一的 UUID 作為標(biāo)識(shí)符。在 Android 開(kāi)發(fā)中,建立藍(lán)牙連接后,我們說(shuō)的通過(guò)藍(lán)牙發(fā)送數(shù)據(jù)給外圍設(shè)備就是往這些 Characteristic 中的 Value 字段寫(xiě)入數(shù)據(jù);外圍設(shè)備發(fā)送數(shù)據(jù)給手機(jī)就是監(jiān)聽(tīng)這些 Charateristic 中的 Value 字段有沒(méi)有變化,如果發(fā)生了變化,手機(jī)的 BLE API 就會(huì)收到一個(gè)監(jiān)聽(tīng)的回調(diào)。

      Android BLE API 簡(jiǎn)介

      BluetoothAdapter BluetoothAdapter 擁有基本的藍(lán)牙操作,例如開(kāi)啟藍(lán)牙掃描,使用已知的 MAC 地址 (BluetoothAdapter#getRemoteDevice)實(shí)例化一個(gè) BluetoothDevice 用于連接藍(lán)牙設(shè)備的操作等等。

      BluetoothDevice 代表一個(gè)遠(yuǎn)程藍(lán)牙設(shè)備。這個(gè)類可以讓你連接所代表的藍(lán)牙設(shè)備或者獲取一些有關(guān)它的信息,例如它的名字,地址和綁定狀態(tài)等等。

      BluetoothGatt 這個(gè)類提供了 Bluetooth GATT 的基本功能。例如重新連接藍(lán)牙設(shè)備,發(fā)現(xiàn)藍(lán)牙設(shè)備的 Service 等等。

      BluetoothGattService 這一個(gè)類通過(guò) BluetoothGatt#getService 獲得,如果當(dāng)前服務(wù)不可見(jiàn)那么將返回一個(gè) null。這一個(gè)類對(duì)應(yīng)上面說(shuō)過(guò)的 Service。我們可以通過(guò)這個(gè)類的 getCharacteristic(UUID uuid) 進(jìn)一步獲取 Characteristic 實(shí)現(xiàn)藍(lán)牙數(shù)據(jù)的雙向傳輸。

      BluetoothGattCharacteristic 這個(gè)類對(duì)應(yīng)上面提到的 Characteristic。通過(guò)這個(gè)類定義需要往外圍設(shè)備寫(xiě)入的數(shù)據(jù)和讀取外圍設(shè)備發(fā)送過(guò)來(lái)的數(shù)據(jù)。

      二、開(kāi)始使用

      1.聲明權(quán)限,在AndroidManifest.xml里面聲明:

      <uses-permission android:name="android.permission.BLUETOOTH"/>
      <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
      在API21(Android5.0)之后還需要加:

      <uses-feature android:name="android.hardware.location.gps" />
      在Android6.0以后還需要加:

      <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
      好了,權(quán)限聲明完成就到了我們的代碼環(huán)節(jié)

      2.初始化BluetoothAdapter

      private BluetoothAdapter mAdapter;
      BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
      mAdapter = bluetoothManager.getAdapter();

      3.如果藍(lán)牙沒(méi)有打開(kāi)先打開(kāi)藍(lán)牙

      if (mAdapter == null || !mAdapter.isEnabled()) {
          // 彈對(duì)話框的形式提示用戶開(kāi)啟藍(lán)牙
          //startActivityForResult(new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE), 1);  
         mBluetoothAdapter.enable();
      }

      4.掃描設(shè)備

      掃描設(shè)備有兩種,一種是過(guò)濾特別的服務(wù)掃描,一種是全部掃描

      下面代碼演示全部掃描

      mAdapter.startLeScan(mLeScanCallback); // 開(kāi)始掃描

      private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
      
         @Override
         public void onLeScan(final BluetoothDevice device, int rssi,
               byte[] scanRecord) {    
      Log.i("掃描到",device.getName()+"rssi"+rssi);
      }};停止掃描

      mAdapter.stopLeScan(mLeScanCallback);   // 停止掃描

      5.連接GATT服務(wù)端

      連接藍(lán)牙設(shè)備可以通過(guò) BluetoothDevice#ConnectGatt 方法連接,也可以通過(guò) BluetoothGatt#connect 方法進(jìn)行重新連接。以下分別是兩個(gè)方法的官方說(shuō)明:

      1. BluetoothDevice#connectGatt
      2. BluetoothGatt connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback)

      第二個(gè)參數(shù)表示是否需要自動(dòng)連接。如果設(shè)置為 true, 表示如果設(shè)備斷開(kāi)了,會(huì)不斷的嘗試自動(dòng)連接。設(shè)置為 false 表示只進(jìn)行一次連接嘗試。

      第三個(gè)參數(shù)是連接后進(jìn)行的一系列操作的回調(diào),例如連接和斷開(kāi)連接的回調(diào),發(fā)現(xiàn)服務(wù)的回調(diào),成功寫(xiě)入數(shù)據(jù),成功讀取數(shù)據(jù)的回調(diào)等等。

      BluetoothDevice device = mAdapter.getRemoteDevice(address);
      device.connectGatt(this, false, mGattCallback);
      private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
          @Override
          public void onConnectionStateChange(BluetoothGatt gatt, int status,
                                              int newState) {
              
          }
      
          @Override
          public void onServicesDiscovered(BluetoothGatt gatt, int status) {
              
             
          }
      
      
      
          @Override
          public void onCharacteristicRead(BluetoothGatt gatt,
                                           BluetoothGattCharacteristic characteristic, int status) {
             
                
          }
      
          @Override
          public void onCharacteristicChanged(BluetoothGatt gatt,
                                              BluetoothGattCharacteristic characteristic) {
             
          }
      };
      當(dāng)調(diào)用藍(lán)牙的連接方法之后,藍(lán)牙會(huì)異步執(zhí)行藍(lán)牙連接的操作,如果連接成功會(huì)回調(diào) BluetoothGattCalbackl#onConnectionStateChange 方法。這個(gè)方法運(yùn)行的線程是一個(gè) Binder 線程,所以不建議直接在這個(gè)線程處理耗時(shí)的任務(wù),因?yàn)檫@可能導(dǎo)致藍(lán)牙相關(guān)的線程被阻塞。

      這一個(gè)方法有三個(gè)參數(shù),第一個(gè)就藍(lán)牙設(shè)備的 Gatt 服務(wù)連接類。

      第二個(gè)參數(shù)代表是否成功執(zhí)行了連接操作,如果為 BluetoothGatt.GATT_SUCCESS 表示成功執(zhí)行連接操作,第三個(gè)參數(shù)才有效,否則說(shuō)明這次連接嘗試不成功。根據(jù)網(wǎng)上大部分人的說(shuō)法,這是因?yàn)?Android 最多支持連接 6 到 7 個(gè)左右的藍(lán)牙設(shè)備,如果超出了這個(gè)數(shù)量就無(wú)法再連接了。所以當(dāng)我們斷開(kāi)藍(lán)牙設(shè)備的連接時(shí),還必須調(diào)用 BluetoothGatt#close 方法釋放連接資源。

      第三個(gè)參數(shù)代表當(dāng)前設(shè)備的連接狀態(tài),如果 newState == BluetoothProfile.STATE_CONNECTED 說(shuō)明設(shè)備已經(jīng)連接,可以進(jìn)行下一步的操作了(發(fā)現(xiàn)藍(lán)牙服務(wù),也就是 Service)。當(dāng)藍(lán)牙設(shè)備斷開(kāi)連接時(shí),這一個(gè)方法也會(huì)被回調(diào),其中的 newState == BluetoothProfile.STATE_DISCONNECTED。

      6.發(fā)現(xiàn)服務(wù)

      在成功連接到藍(lán)牙設(shè)備之后才能進(jìn)行這一個(gè)步驟,調(diào)用 BluetoothGatt#discoverService 這一個(gè)方法。當(dāng)這一個(gè)方法被調(diào)用之后,系統(tǒng)會(huì)異步執(zhí)行發(fā)現(xiàn)服務(wù)的過(guò)程,直到 BluetoothGattCallback#onServicesDiscovered 被系統(tǒng)回調(diào)之后,手機(jī)設(shè)備和藍(lán)牙設(shè)備才算是真正建立了可通信的連接。

      if (newState == BluetoothProfile.STATE_CONNECTED) {
          mBluetoothGatt.discoverServices();
      }
      

      7.讀寫(xiě)設(shè)備

      當(dāng)我們發(fā)現(xiàn)服務(wù)之后就可以通過(guò) BluetoothGatt#getService 獲取 BluetoothGattService,接著通過(guò) BluetoothGattService#getCharactristic 獲取 BluetoothGattCharactristic。

      通過(guò) BluetoothGattCharactristic#readCharacteristic 方法可以通知系統(tǒng)去讀取特定的數(shù)據(jù)。如果系統(tǒng)讀取到了藍(lán)牙設(shè)備發(fā)送過(guò)來(lái)的數(shù)據(jù)就會(huì)調(diào)用 BluetoothGattCallback#onCharacteristicRead 方法。

      通過(guò) BluetoothGattCharacteristic#getValue 可以讀取到藍(lán)牙設(shè)備的數(shù)據(jù)。

      // 讀取數(shù)據(jù)
      BluetoothGattService service = mBluetoothGatt.getService("需要讀取的服務(wù)");
      BluetoothGattCharacteristic characteristic = service.getCharacteristic("需要讀取的特征");
      mBluetoothGatt.readCharacteristic(characteristic);
      /**
       * BLE終端數(shù)據(jù)被讀的事件
       */
      @Override
      public void onCharacteristicRead(BluetoothGatt gatt,
                                       BluetoothGattCharacteristic characteristic, int status) {
      
          Log.i("onCharacteristicRead","讀取的回調(diào)"+characteristic.getValue());
      
      
      }

      寫(xiě)

      和讀取數(shù)據(jù)一樣,在執(zhí)行寫(xiě)入數(shù)據(jù)前需要獲取到 BluetoothGattCharactristic。接著執(zhí)行一下步驟:

      1. 調(diào)用 BluetoothGattCharactristic#setValue 傳入需要寫(xiě)入的數(shù)據(jù)(藍(lán)牙最多單次1支持 20 個(gè)字節(jié)數(shù)據(jù)的傳輸,如果需要傳輸?shù)臄?shù)據(jù)大于這一個(gè)字節(jié)則需要分包傳輸)。
      2. 調(diào)用 BluetoothGattCharactristic#writeCharacteristic 方法通知系統(tǒng)異步往設(shè)備寫(xiě)入數(shù)據(jù)。
      3. 系統(tǒng)回調(diào) BluetoothGattCallback#onCharacteristicWrite 方法通知數(shù)據(jù)已經(jīng)完成寫(xiě)入。此時(shí),我們需要執(zhí)行 BluetoothGattCharactristic#getValue 方法檢查一下寫(xiě)入的數(shù)據(jù)是否我們需要發(fā)送的數(shù)據(jù),如果不是按照項(xiàng)目的需要判斷是否需要重發(fā)。
      BluetoothGattService service = mBluetoothGatt.getService("需要寫(xiě)的服務(wù)");
      BluetoothGattCharacteristic characteristic = service.getCharacteristic("需要寫(xiě)的特征");
      characteristic.setValue("需要寫(xiě)入的數(shù)據(jù)");
      mBluetoothGatt.writeCharacteristic(characteristic);
      public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
          if(!characteristic.getValue().equals("需要寫(xiě)入的數(shù)據(jù)")) {
              // 執(zhí)行重發(fā)策略
              gatt.writeCharacteristic(characteristic);
          }
      }

      通知

      mBluetoothGatt.setCharacteristicNotification(characteristic, true);
      
      BluetoothGattDescriptor descriptor = characteristic.getDescriptor(
              UUID.fromString(""));
      descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);//或者descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
      
      mBluetoothGatt.writeDescriptor(descriptor);
      然后來(lái)的通知就會(huì)回調(diào)在

      public void onCharacteristicChanged(BluetoothGatt gatt,
                                          BluetoothGattCharacteristic characteristic) {
      
      }

      8.斷開(kāi)連接

      當(dāng)我們連接藍(lán)牙設(shè)備完成一系列的藍(lán)牙操作之后就可以斷開(kāi)藍(lán)牙設(shè)備的連接了。通過(guò) BluetoothGatt#disconnect 可以斷開(kāi)正在連接的藍(lán)牙設(shè)備。當(dāng)這一個(gè)方法被調(diào)用之后,系統(tǒng)會(huì)異步回調(diào) BluetoothGattCallback#onConnectionStateChange 方法。通過(guò)這個(gè)方法的 newState 參數(shù)可以判斷是連接成功還是斷開(kāi)成功的回調(diào)。由于 Android 藍(lán)牙連接設(shè)備的資源有限,當(dāng)我們執(zhí)行斷開(kāi)藍(lán)牙操作之后必須執(zhí)行 BluetoothGatt#close 方法釋放資源。需要注意的是通過(guò) BluetoothGatt#close 方法也可以執(zhí)行斷開(kāi)藍(lán)牙的操作,不過(guò) BluetoothGattCallback#onConnectionStateChange 將不會(huì)收到任何回調(diào)。此時(shí)如果執(zhí)行 BluetoothGatt#connect 方法會(huì)得到一個(gè)藍(lán)牙 API 的空指針異常。所以,我們推薦的寫(xiě)法是當(dāng)藍(lán)牙成功連接之后,通過(guò) BluetoothGatt#disconnect 斷開(kāi)藍(lán)牙的連接,緊接著在 BluetoothGattCallback#onConnectionStateChange 執(zhí)行 BluetoothGatt#close 方法釋放資源。

      @Override
      public void onConnectionStateChange(final BluetoothGatt gatt, final int status,
                                          final int newState) {
          Log.d(TAG, "onConnectionStateChange: thread "
                  + Thread.currentThread() + " status " + newState);
      
          if (status != BluetoothGatt.GATT_SUCCESS) {
              String err = "Cannot connect device with error status: " + status;
              // 當(dāng)嘗試連接失敗的時(shí)候調(diào)用 disconnect 方法是不會(huì)引起這個(gè)方法回調(diào)的,所以這里
              //   直接回調(diào)就可以了。
              gatt.close();
              Log.e(TAG, err);
              return;
          }
      
          if (newState == BluetoothProfile.STATE_CONNECTED) {
              gatt.discoverService();
          } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
              gatt.close();
          }
      }

        本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評(píng)論

        發(fā)表

        請(qǐng)遵守用戶 評(píng)論公約

        類似文章 更多