一、前言
在上一篇文章Android 藍牙BLE開發從官方源碼demo開始(一)我們已經看了官方的demo,知道了怎么開始配置Android藍牙4.0,并且也成功地進行掃描并獲取回調的藍牙設備參數,然后對參數進行處理展示,其中第一個參數device,表示一個遠程藍牙設備,里面有它獨有的藍牙地址Address和Name;我們要拿到這個設備Address進行藍牙連接和讀寫操作。
谷歌給我們提供了官方源碼demo:
https://github.com/googlesamples/android-BluetoothLeGatt
接下來我們繼續來學習谷歌官方給我們提供的藍牙BLE源碼
二、創建BluetoothLeService服務類并初始化藍牙連接
在官方demo中,藍牙ble的連接和讀寫操作都是在DeviceControlActivity中實現,可以下載demo源碼,編譯運行一遍!
來到此Activity,我們先看onCreate()方法可知,程序先執行bindService開啟了一個服務
Intent gattServiceIntent = new Intent(this, BluetoothLeService.class);
bindService(gattServiceIntent, mServiceConnection, BIND_AUTO_CREATE);
并在服務回調已經成功連接時,獲取了BlueToohtLeService的實例,接著就執行藍牙連接操作:
// Code to manage Service lifecycle.
private final ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder service) {
mBluetoothLeService = ((BluetoothLeService.LocalBinder) service).getService();
if (!mBluetoothLeService.initialize()) {
Log.e(TAG, "Unable to initialize Bluetooth");
finish();
}
// Automatically connects to the device upon successful start-up initialization.
mBluetoothLeService.connect(mDeviceAddress);
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
mBluetoothLeService = null;
}
};
這個BlueToohtLeService類既然是服務類,那它父類肯定是繼承于Service;接著實現了Service的先進入onBind()方法;
1.onBind()是使用bindService開啟的服務才會有回調的一個方法。
這里官方demo在onBind()方法給我們的Activity返回了BluetoothLeService實例,方便Activity后續的連接和讀寫操作;
private final IBinder mBinder = new LocalBinder();
public class LocalBinder extends Binder {
BluetoothLeService getService() {
return BluetoothLeService.this;
}
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
2.當服務調用unbindService時,服務的生命周期將會進入onUnbind()方法;接著執行了關閉藍牙的方法;
@Override
public boolean onUnbind(Intent intent) {
// After using a given device, you should make sure that BluetoothGatt.close() is called
// such that resources are cleaned up properly. In this particular example, close() is
// invoked when the UI is disconnected from the Service.
close();
return super.onUnbind(intent);
}
3.initialize() 初始化藍牙適配器;接著在這demo里這個方法是在服務建立后在Activity通過拿到BlueToohtLeService實例調用的。
/**
* Initializes a reference to the local Bluetooth adapter.
*
* @return Return true if the initialization is successful.
*/
public boolean initialize() {
// For API level 18 and above, get a reference to BluetoothAdapter through
// BluetoothManager.
if (mBluetoothManager == null) {
mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
if (mBluetoothManager == null) {
Log.e(TAG, "Unable to initialize BluetoothManager.");
return false;
}
}
mBluetoothAdapter = mBluetoothManager.getAdapter();
if (mBluetoothAdapter == null) {
Log.e(TAG, "Unable to obtain a BluetoothAdapter.");
return false;
}
return true;
}
4.connect()方法 傳入藍牙地址進行連接藍牙操作;先判斷藍牙適配器是否為空,然后判斷是否剛斷開需要重連的設備,否則就通過藍牙適配器獲取BluetoothGatt實例去連接藍牙操作,后續還會使用到BluetoothGatt去讀寫操作和斷開、關閉操作;
public boolean connect(final String address) {
if (mBluetoothAdapter == null || address == null) {
Log.w(TAG, "BluetoothAdapter not initialized or unspecified address.");
return false;
}
// Previously connected device. Try to reconnect.
// 以前連接的設備。 嘗試重新連接。
if (mBluetoothDeviceAddress != null && address.equals(mBluetoothDeviceAddress)
&& mBluetoothGatt != null) {
Log.d(TAG, "Trying to use an existing mBluetoothGatt for connection.");
if (mBluetoothGatt.connect()) {
mConnectionState = STATE_CONNECTING;
return true;
} else {
return false;
}
}
final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
if (device == null) {
Log.w(TAG, "Device not found. Unable to connect.");
return false;
}
// We want to directly connect to the device, so we are setting the autoConnect 我們想直接連接到設備,因此我們設置autoConnect
// parameter to false.
mBluetoothGatt = device.connectGatt(this, false, mGattCallback);
Log.d(TAG, "Trying to create a new connection.");
mBluetoothDeviceAddress = address;
mConnectionState = STATE_CONNECTING;
return true;
}
5.BluetoothGattCallback 回調;這個回調可以說很重要,核心部分,主要對BluetoothGatt的藍牙連接、斷開、讀、寫、特征值變化等的回調監聽,然后我們可以將這些回調信息通過廣播機制傳播回給廣播監聽器。
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) {
}
};
三、廣播監聽器
在這個官方demo中,就是使用了廣播來作為activity和service之間的數據傳遞;繼續回到源碼:activity開啟前面所說的服務之后,就注冊了這個mGattUpdateReceiver廣播;
registerReceiver(mGattUpdateReceiver, makeGattUpdateIntentFilter());
if (mBluetoothLeService != null) {
final boolean result = mBluetoothLeService.connect(mDeviceAddress);
Log.d(TAG, "Connect request result=" + result) ;
}
private static IntentFilter makeGattUpdateIntentFilter() {
final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(BluetoothLeService.ACTION_GATT_CONNECTED);
intentFilter.addAction(BluetoothLeService.ACTION_GATT_DISCONNECTED);
intentFilter.addAction(BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED);
intentFilter.addAction(BluetoothLeService.ACTION_DATA_AVAILABLE);
return intentFilter;
}
關于這個廣播的回調監聽如下:有注釋就不多解釋了,它的作用就是接收從service發送回來的信息;上文有說到BluetoothGattCallback,就是從這里發送廣播的。
// Handles various events fired by the Service. 處理服務部門發起的各種事件
// ACTION_GATT_CONNECTED: connected to a GATT server. 連接到GATT服務器。
// ACTION_GATT_DISCONNECTED: disconnected from a GATT server. 與GATT服務器斷開連接。
// ACTION_GATT_SERVICES_DISCOVERED: discovered GATT services.發現GATT服務
// ACTION_DATA_AVAILABLE: received data from the device. This can be a result of read
// or notification operations. 從設備接收數據。 這可能是閱讀的結果
// //或通知操作。
private final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (BluetoothLeService.ACTION_GATT_CONNECTED.equals(action)) {
mConnected = true;
updateConnectionState(R.string.connected);
invalidateOptionsMenu();
} else if (BluetoothLeService.ACTION_GATT_DISCONNECTED.equals(action)) {
mConnected = false;
updateConnectionState(R.string.disconnected);
invalidateOptionsMenu();
clearUI();
} else if (BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED.equals(action)) {
// Show all the supported services and characteristics on the user interface.
displayGattServices(mBluetoothLeService.getSupportedGattServices());
} else if (BluetoothLeService.ACTION_DATA_AVAILABLE.equals(action)) {
displayData(intent.getStringExtra(BluetoothLeService.EXTRA_DATA));
}
}
};
這里留意一下:當連接成功后,首先service那邊會發現服務特征值,通過廣播傳輸回來,然后執行下面的方法:
displayGattServices(mBluetoothLeService.getSupportedGattServices());
四、其他方法
- setCharacteristicNotification();調用此方法開啟特征值的通知;
mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
2.開啟讀,我們可以用如下方法,但是此方法有個缺點:要不斷輪詢 才能達到不斷監聽;
mBluetoothGatt.readCharacteristic(characteristic);
如果成功,將返回BluetoothGattCallback回調 進入其如下方法
@Override
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
}
或
使用如下方法,傳入特征值,true
mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
如果成功,將返回BluetoothGattCallback回調 進入其如下方法
@Override
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
}
具體選擇哪種方法就要看具體需求了。
3.還有一個很重要的方法,demo沒有給出例子的:
mBluetoothGatt.writeCharacteristic(characteristic);
這是向藍牙設備寫入數據,幾乎都會用到的。
如果成功,將返回BluetoothGattCallback回調 進入其如下方法
@Override
public void onCharacteristicWrite(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status) {
}
- disconnect();調用BluetoothGatt.disconnect()斷開藍牙連接;
public void disconnect() {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
mBluetoothGatt.disconnect();
}
5.close();關閉藍牙
/**
* After using a given BLE device, the app must call this method to ensure resources are
* released properly.
*/
public void close() {
if (mBluetoothGatt == null) {
return;
}
mBluetoothGatt.close();
mBluetoothGatt = null;
}
最后,關于Android藍牙BLE的使用在此結束,我從下載官方demo到一步一步地去理解具體的調用,最后已經算是走通了整個藍牙開發流程,如果想再深入點的話就要考慮具體的底層實現,和真實項目中怎么去更好地封裝!
掃一掃關注我的微信公眾號:程序猿在廣東
my二維碼.jpg