一思犁、前言
在上一篇文章Android 藍(lán)牙BLE開發(fā)從官方源碼demo開始(一)我們已經(jīng)看了官方的demo幔欧,知道了怎么開始配置Android藍(lán)牙4.0包警,并且也成功地進(jìn)行掃描并獲取回調(diào)的藍(lán)牙設(shè)備參數(shù),然后對參數(shù)進(jìn)行處理展示伯顶,其中第一個(gè)參數(shù)device,表示一個(gè)遠(yuǎn)程藍(lán)牙設(shè)備骆膝,里面有它獨(dú)有的藍(lán)牙地址Address和Name祭衩;我們要拿到這個(gè)設(shè)備Address進(jìn)行藍(lán)牙連接和讀寫操作。
谷歌給我們提供了官方源碼demo:
https://github.com/googlesamples/android-BluetoothLeGatt
接下來我們繼續(xù)來學(xué)習(xí)谷歌官方給我們提供的藍(lán)牙BLE源碼
二阅签、創(chuàng)建BluetoothLeService服務(wù)類并初始化藍(lán)牙連接
在官方demo中掐暮,藍(lán)牙ble的連接和讀寫操作都是在DeviceControlActivity中實(shí)現(xiàn),可以下載demo源碼政钟,編譯運(yùn)行一遍路克!
來到此Activity,我們先看onCreate()方法可知养交,程序先執(zhí)行bindService開啟了一個(gè)服務(wù)
Intent gattServiceIntent = new Intent(this, BluetoothLeService.class);
bindService(gattServiceIntent, mServiceConnection, BIND_AUTO_CREATE);
并在服務(wù)回調(diào)已經(jīng)成功連接時(shí)精算,獲取了BlueToohtLeService的實(shí)例,接著就執(zhí)行藍(lán)牙連接操作:
// 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;
}
};
這個(gè)BlueToohtLeService類既然是服務(wù)類碎连,那它父類肯定是繼承于Service灰羽;接著實(shí)現(xiàn)了Service的先進(jìn)入onBind()方法;
1.onBind()是使用bindService開啟的服務(wù)才會(huì)有回調(diào)的一個(gè)方法鱼辙。
這里官方demo在onBind()方法給我們的Activity返回了BluetoothLeService實(shí)例廉嚼,方便Activity后續(xù)的連接和讀寫操作;
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.當(dāng)服務(wù)調(diào)用unbindService時(shí)座每,服務(wù)的生命周期將會(huì)進(jìn)入onUnbind()方法前鹅;接著執(zhí)行了關(guān)閉藍(lán)牙的方法;
@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() 初始化藍(lán)牙適配器峭梳;接著在這demo里這個(gè)方法是在服務(wù)建立后在Activity通過拿到BlueToohtLeService實(shí)例調(diào)用的舰绘。
/**
* 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()方法 傳入藍(lán)牙地址進(jìn)行連接藍(lán)牙操作;先判斷藍(lán)牙適配器是否為空葱椭,然后判斷是否剛斷開需要重連的設(shè)備捂寿,否則就通過藍(lán)牙適配器獲取BluetoothGatt實(shí)例去連接藍(lán)牙操作,后續(xù)還會(huì)使用到BluetoothGatt去讀寫操作和斷開孵运、關(guān)閉操作秦陋;
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.
// 以前連接的設(shè)備。 嘗試重新連接治笨。
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 我們想直接連接到設(shè)備驳概,因此我們設(shè)置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 回調(diào)赤嚼;這個(gè)回調(diào)可以說很重要,核心部分顺又,主要對BluetoothGatt的藍(lán)牙連接更卒、斷開、讀稚照、寫蹂空、特征值變化等的回調(diào)監(jiān)聽,然后我們可以將這些回調(diào)信息通過廣播機(jī)制傳播回給廣播監(jiān)聽器果录。
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) {
}
};
三上枕、廣播監(jiān)聽器
在這個(gè)官方demo中,就是使用了廣播來作為activity和service之間的數(shù)據(jù)傳遞弱恒;繼續(xù)回到源碼:activity開啟前面所說的服務(wù)之后辨萍,就注冊了這個(gè)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;
}
關(guān)于這個(gè)廣播的回調(diào)監(jiān)聽如下:有注釋就不多解釋了返弹,它的作用就是接收從service發(fā)送回來的信息分瘦;上文有說到BluetoothGattCallback,就是從這里發(fā)送廣播的琉苇。
// Handles various events fired by the Service. 處理服務(wù)部門發(fā)起的各種事件
// ACTION_GATT_CONNECTED: connected to a GATT server. 連接到GATT服務(wù)器嘲玫。
// ACTION_GATT_DISCONNECTED: disconnected from a GATT server. 與GATT服務(wù)器斷開連接。
// ACTION_GATT_SERVICES_DISCOVERED: discovered GATT services.發(fā)現(xiàn)GATT服務(wù)
// ACTION_DATA_AVAILABLE: received data from the device. This can be a result of read
// or notification operations. 從設(shè)備接收數(shù)據(jù)并扇。 這可能是閱讀的結(jié)果
// //或通知操作去团。
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));
}
}
};
這里留意一下:當(dāng)連接成功后,首先service那邊會(huì)發(fā)現(xiàn)服務(wù)特征值穷蛹,通過廣播傳輸回來土陪,然后執(zhí)行下面的方法:
displayGattServices(mBluetoothLeService.getSupportedGattServices());
四、其他方法
- setCharacteristicNotification()肴熏;調(diào)用此方法開啟特征值的通知鬼雀;
mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
2.開啟讀,我們可以用如下方法蛙吏,但是此方法有個(gè)缺點(diǎn):要不斷輪詢 才能達(dá)到不斷監(jiān)聽源哩;
mBluetoothGatt.readCharacteristic(characteristic);
如果成功,將返回BluetoothGattCallback回調(diào) 進(jìn)入其如下方法
@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回調(diào) 進(jìn)入其如下方法
@Override
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
}
具體選擇哪種方法就要看具體需求了泼诱。
3.還有一個(gè)很重要的方法坛掠,demo沒有給出例子的:
mBluetoothGatt.writeCharacteristic(characteristic);
這是向藍(lán)牙設(shè)備寫入數(shù)據(jù),幾乎都會(huì)用到的。
如果成功屉栓,將返回BluetoothGattCallback回調(diào) 進(jìn)入其如下方法
@Override
public void onCharacteristicWrite(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status) {
}
- disconnect()舷蒲;調(diào)用BluetoothGatt.disconnect()斷開藍(lán)牙連接;
public void disconnect() {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
mBluetoothGatt.disconnect();
}
5.close();關(guān)閉藍(lán)牙
/**
* 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;
}
最后友多,關(guān)于Android藍(lán)牙BLE的使用在此結(jié)束阿纤,我從下載官方demo到一步一步地去理解具體的調(diào)用,最后已經(jīng)算是走通了整個(gè)藍(lán)牙開發(fā)流程夷陋,如果想再深入點(diǎn)的話就要考慮具體的底層實(shí)現(xiàn),和真實(shí)項(xiàng)目中怎么去更好地封裝胰锌!
掃一掃關(guān)注我的微信公眾號:程序猿在廣東
my二維碼.jpg