上節咱們已經能夠鏈接上藍牙設備了。java
本節咱們就要獲取手環的電池電量和計步啦。android
在介紹這個以前咱們須要先了解下什麼是 服務 什麼是 UUID編程
咱們記得上節中咱們item監聽事件的回調的返回值是BluetoothGatt 類型的,還記得麼?嘿嘿。數組
返回的bluetoothgatt中包含一個或多個BluetoothGattService(服務)app
每一個service包含一個或多個characteristic(特徵值)異步
每一個特徵值包含一個value 和多個 descriptor(注意看啊!是一個value)ide
這些對於本項目來講某個特徵值的value中就包含了記錄的步數。(很遺憾我折騰了好久也沒找到電池電量,不得不捨棄展現電池電量的想法)ui
先熟悉下下面的圖片吧~~this
(百度腦圖)spa
在瞭解下UUID 上圖中每一個藍牙設備都有本身的MAC 地址有了這個地址 咱們就能夠鏈接這個設備。
鏈接上設備後會的到設備的服務就是上圖中的Gattservice 這每一個service都有個固定的UUID以標識區分
每一個service又包含多個的characteristic 這些特徵值也有惟一的UUID 這些UUID就是咱們編程須要的,
獲取到characteristic對應的UUID就意味着獲取到該characteristic提供的功能或者數據。
特徵值對應的UUID所實現的功能是由硬件工程師決定的。
由於小米手環的硬件工程師咱們沒有聯繫方式,何況人家也確定不會告訴我全部功能對應的UUID
所以咱們只好本身對應數值來找了。
簡單說 上圖的每一個characteristic 都對應一個UUID 這些UUID對應了設備的不一樣功能
手環爲例:
控制手環震動的 UUID :00002a06-0000-1000-8000-00805f9b34fb 手機向該 UUID 寫入 0x01 或者 0x02 時手環都會震動,01強度弱於 02
計步的 UUID :0000ff06-0000-1000-8000-00805f9b34fb 讀取該UUID下的value數組 第0 個數據就是 步數
首先咱們來獲取下計步數吧
通過一番折騰我終於找到了小米手環對應步數的 UUID :0000ff06-0000-1000-8000-00805f9b34fb
gattcallback 回調方法中找到 onServicesDiscovered
添加以下代碼:
@Override public void onServicesDiscovered(BluetoothGatt gatt, int status) { super.onServicesDiscovered(gatt, status); //尋找到服務時 if (status == bluetoothGatt.GATT_SUCCESS) { final List<BluetoothGattService> services = bluetoothGatt.getServices(); runOnUiThread(new Runnable() { @Override public void run() { //List<String> serlist = new ArrayList<>(); for (final BluetoothGattService bluetoothGattService : services) { bluetoothGattServices = bluetoothGattService; Log.i(TAG, "onServicesDiscovered: " + bluetoothGattService.getUuid()); List<BluetoothGattCharacteristic> charc = bluetoothGattService.getCharacteristics(); for (BluetoothGattCharacteristic charac : charc) { Log.i(TAG, "run: " + charac.getUuid()); //找到透傳特徵值 // 00002a06-0000-1000-8000-00805f9b34fb 小米手環震動特徵值 0x01震動 0x02強震 if (charac.getUuid().toString().equals("00002a06-0000-1000-8000-00805f9b34fb")) { //設備 震動特徵值 characteristic_zd = charac; } else if (charac.getUuid().toString().equals("0000ff06-0000-1000-8000-00805f9b34fb")) { //設備 步數 characteristic_jb = charac; bluetoothGatt.readCharacteristic(characteristic_jb); Log.i(TAG, "run: 正在嘗試讀取步數"); } else if (charac.getUuid().toString().equals("")) { //設備 電量特徵值 } } serviceslist.add(bluetoothGattService.getUuid().toString()); } } }); } }
註釋寫的很清楚
我用 characteristic_zd 記住震動的特徵值
用 characteristic_jb 記住計步的
記住計步特徵值後使用 bluetoothGatt 提供的read方法並傳人相應特徵值。該方法爲異步方法他的返回內容會由
回調中的 onCharacteristicRead 方法接收到
找到該方法添加以下代碼:
if (status == bluetoothGatt.GATT_SUCCESS) { final int sum = characteristic.getValue()[0]; runOnUiThread(new Runnable() { @Override public void run() { jibu.setText("走了" + sum + "步"); } }); Log.e(TAG, "onCharacteristicRead: " + characteristic.getValue()[0]); }
方法的參數中status表示狀態,爲 bluetoothGatt.GATT_SUCCESS 時表示成功獲取返回
由於在異步方法中,想要操做UI線程,因而就用了 runOnUiThread 方法。顯示出來步數便可。
好了下面貼出完整主Activity代碼:
MainActivity.java:
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
package com.wbnq.shouhuan; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothGatt; import android.bluetooth.BluetoothGattCallback; import android.bluetooth.BluetoothGattCharacteristic; import android.bluetooth.BluetoothGattDescriptor; import android.bluetooth.BluetoothGattService; import android.bluetooth.BluetoothManager; import android.content.Intent; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; import java.util.ArrayList; import java.util.List; import java.util.UUID; public class MainActivity extends AppCompatActivity implements View.OnClickListener { private Button saomiao, duanzhen, changzhen, buting, tingxia; private TextView jibu, dianliang, lianjiezhuangtai; private ListView list; public static String TAG = "shouhuan-MainActivity"; BluetoothAdapter bluetoothAdapter; BluetoothGatt bluetoothGatt; List<BluetoothDevice> deviceList = new ArrayList<>(); List<String> serviceslist = new ArrayList<String>(); BluetoothDevice bluetoothDevice; BluetoothGattService bluetoothGattServices; BluetoothGattCharacteristic characteristic_zd, characteristic_jb; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); //藍牙管理,這是系統服務能夠經過getSystemService(BLUETOOTH_SERVICE)的方法獲取實例 BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE); //經過藍牙管理實例獲取適配器,而後經過掃描方法(scan)獲取設備(device) bluetoothAdapter = bluetoothManager.getAdapter(); } private void initView() { saomiao = (Button) findViewById(R.id.saomiao); duanzhen = (Button) findViewById(R.id.zhendong); changzhen = (Button) findViewById(R.id.changzhen); buting = (Button) findViewById(R.id.buting); tingxia = (Button) findViewById(R.id.tingxia); list = (ListView) findViewById(R.id.list); jibu = (TextView) findViewById(R.id.jibu); dianliang = (TextView) findViewById(R.id.dianliang); lianjiezhuangtai = (TextView) findViewById(R.id.lianjiezhuangtai); saomiao.setOnClickListener(this); duanzhen.setOnClickListener(this); changzhen.setOnClickListener(this); buting.setOnClickListener(this); tingxia.setOnClickListener(this); //item 監聽事件 list.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) { bluetoothDevice = deviceList.get(i); //鏈接設備的方法,返回值爲bluetoothgatt類型 bluetoothGatt = bluetoothDevice.connectGatt(MainActivity.this, false, gattcallback); lianjiezhuangtai.setText("鏈接" + bluetoothDevice.getName() + "中..."); } }); } @Override public void onClick(View view) { switch (view.getId()) { case R.id.saomiao: //開始掃描前開啓藍牙 Intent turn_on = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(turn_on, 0); Toast.makeText(MainActivity.this, "藍牙已經開啓", Toast.LENGTH_SHORT).show(); Thread scanThread = new Thread(new Runnable() { @Override public void run() { Log.i("TAG", "run: saomiao ..."); saomiao(); } }); scanThread.start(); lianjiezhuangtai.setText("正在掃描"); break; case R.id.zhendong: break; case R.id.changzhen: break; case R.id.buting: break; case R.id.tingxia: break; case R.id.list: break; } } public void saomiao() { deviceList.clear(); bluetoothAdapter.startLeScan(callback); } //掃描回調 public BluetoothAdapter.LeScanCallback callback = new BluetoothAdapter.LeScanCallback() { @Override public void onLeScan(final BluetoothDevice bluetoothDevice, int i, byte[] bytes) { Log.i("TAG", "onLeScan: " + bluetoothDevice.getName() + "/t" + bluetoothDevice.getAddress() + "/t" + bluetoothDevice.getBondState()); //重複過濾方法,列表中包含不應設備才加入列表中,並刷新列表 if (!deviceList.contains(bluetoothDevice)) { //將設備加入列表數據中 deviceList.add(bluetoothDevice); list.setAdapter(new MyAdapter(MainActivity.this, deviceList)); } } }; private BluetoothGattCallback gattcallback = new BluetoothGattCallback() { @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, final int newState) { super.onConnectionStateChange(gatt, status, newState); runOnUiThread(new Runnable() { @Override public void run() { String status; switch (newState) { //已經鏈接 case BluetoothGatt.STATE_CONNECTED: lianjiezhuangtai.setText("已鏈接"); bluetoothAdapter.stopLeScan(callback); //該方法用於獲取設備的服務,尋找服務 bluetoothGatt.discoverServices(); break; //正在鏈接 case BluetoothGatt.STATE_CONNECTING: lianjiezhuangtai.setText("正在鏈接"); break; //鏈接斷開 case BluetoothGatt.STATE_DISCONNECTED: lianjiezhuangtai.setText("已斷開"); break; //正在斷開 case BluetoothGatt.STATE_DISCONNECTING: lianjiezhuangtai.setText("斷開中"); break; } //pd.dismiss(); } }); } @Override public void onServicesDiscovered(BluetoothGatt gatt, int status) { super.onServicesDiscovered(gatt, status); //尋找到服務時 if (status == bluetoothGatt.GATT_SUCCESS) { final List<BluetoothGattService> services = bluetoothGatt.getServices(); runOnUiThread(new Runnable() { @Override public void run() { //List<String> serlist = new ArrayList<>(); for (final BluetoothGattService bluetoothGattService : services) { bluetoothGattServices = bluetoothGattService; Log.i(TAG, "onServicesDiscovered: " + bluetoothGattService.getUuid()); List<BluetoothGattCharacteristic> charc = bluetoothGattService.getCharacteristics(); for (BluetoothGattCharacteristic charac : charc) { Log.i(TAG, "run: " + charac.getUuid()); //找到透傳特徵值 // 00002a06-0000-1000-8000-00805f9b34fb 小米手環震動特徵值 0x01震動 0x02強震 if (charac.getUuid().toString().equals("00002a06-0000-1000-8000-00805f9b34fb")) { //設備 震動特徵值 characteristic_zd = charac; } else if (charac.getUuid().toString().equals("0000ff06-0000-1000-8000-00805f9b34fb")) { //設備 步數 characteristic_jb = charac; bluetoothGatt.readCharacteristic(characteristic_jb); Log.i(TAG, "run: 正在嘗試讀取步數"); } else if (charac.getUuid().toString().equals("")) { //設備 電量特徵值 } } serviceslist.add(bluetoothGattService.getUuid().toString()); } // ArrayAdapter<String> adapter = new ArrayAdapter<String>( // MainActivity.this, android.R.layout.simple_expandable_list_item_1, serviceslist); //list.setAdapter(adapter); } }); } } @Override public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { super.onCharacteristicRead(gatt, characteristic, status); if (status == bluetoothGatt.GATT_SUCCESS) { final int sum = characteristic.getValue()[0]; runOnUiThread(new Runnable() { @Override public void run() { jibu.setText("走了" + sum + "步"); } }); Log.e(TAG, "onCharacteristicRead: " + characteristic.getValue()[0]); } } @Override public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { super.onCharacteristicWrite(gatt, characteristic, status); } //獲取返回 數據 @Override public void onCharacteristicChanged(BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) { super.onCharacteristicChanged(gatt, characteristic); Log.i(TAG, "onCharacteristicChanged: 獲取回調方法"); Log.e("", "命令:" + HexUtil.encodeHexStr(characteristic.getValue())); final byte[] values = characteristic.getValue(); runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(MainActivity.this, HexUtil.encodeHexStr(values), Toast.LENGTH_SHORT).show(); } }); } }; private boolean enableNotification(boolean enable, BluetoothGattCharacteristic characteristic) { if (bluetoothGatt == null || characteristic == null) return false; if (!bluetoothGatt.setCharacteristicNotification(characteristic, enable)) return false; BluetoothGattDescriptor clientConfig = characteristic.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb")); if (clientConfig == null) return false; if (enable) { clientConfig.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); } else { clientConfig.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE); } return bluetoothGatt.writeDescriptor(clientConfig); } }
今天就寫這些,下次要實現震動方法咯!是否是很激動呢~~
嘿嘿嘿~
你們加油啦~~