您的位置:首页 > 产品设计 > UI/UE

Android BLE 蓝牙学习总结(二):手机作为中央BluetoothGatt的实现

2017-10-30 14:30 676 查看
一、创建中央基本概念

1.1、中央涉及的类有:



说明:为了拿到中央BluetoothGatt,需要经历以下过程:

1、先拿到BluetoothManager:bluetoothManager=(BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE);

2、再拿到BluetoothAdapter:bluetoothAdapter=bluetoothManager.getAdapter();

3、开始扫描:bluetoothAdapter.startLeScan(BluetoothAdpater.LeScanCallback);

4、从LeScanCallback中得到BluetoothDevice:public void onLeScan(BluetoothDevice device,int rssi,byte[] scanRecord){……};

5、用BluetoothDevice得到BluetoothGatt:gatt=device.connectGatt(this,true,gattCallback);

6、接下来调用BluetoothGatt的方法,通过BluetoothGattCallback和周边的BluetoothServer进行交互

1.2、扫描以及读取与写入数据的相关概念:

监听扫描结果:

mLeScanCallback = new BluetoothAdapter.LeScanCallback() {

public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {}

};

device 搜索到的bye设备。

rssi 信号强度

scanRecord 远程设备广告记录的内容(蓝牙名称)

发起连接请求,获得中央。

mBluetoothGatt = device.connectGatt(mContext, false,mGattCallback);

第二个参数autoConnect 如果为false直接立即连接。

true 等待远程设备可用时(在范围内,。。)连接。并不是断开后重新连接。

第三个参数 Gatt callback 。

private BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {};

连接成功后,发送 gatt服务发现请求。

//连接状态改变回调

onConnectionStateChange(BluetoothGatt gatt, int status, int newState){

if(newState == BluetoothProfile.STATE_CONNECTED){

//连接成功后,发送发现服务请求。

mBluetoothGatt.discoverServices();

}

}

//发现服务回调。

public void onServicesDiscovered(BluetoothGatt gatt, int status) {

if(status == BluetoothGatt.GATT_SUCCESS){

//发现成功后,则可以通过下面方法获取service 列表。

mBluetoothGatt.getServices();

}

}

1.3、中央与周边的数据交互过程总结(写入):

1、当点击事件调用该方法时BluetoothGatt.writeCharacteristic(characteristic),

a、系统异步回调onCharacteristicChanged()方法,

b、与此同时服务端:系统回调onCharacteristicWriteRequest()方法,通过该方法的参数value得到客户端发送过来的数据,在该回调方法中调用sendResponse()回复客户端响应成功,接着处理接受的数据,并通过BluetoothGattServer.notityCharacteristicChanged(device,characteristicRead,false)将回应的数据发送给客户端,该回应的数据就通过onCharacteristicChanged()方法的参数传递到客户端。

c、a与b是异步进行的

二、中央实现的案例讲解

2.1、添加权限

<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>


2.2、初始化蓝牙,

1、在onCreate()中检查手机是否支持BLE蓝牙

2、在onResume()中开启蓝牙设备

// Use this check to determine whether BLE is supported on the device.  Then you can
// selectively disable BLE-related features.
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Toast.makeText(this, "ble_not_supported", Toast.LENGTH_SHORT).show();
finish();
}
// Initializes a Bluetooth adapter.  For API level 18 and above, get a reference to
// BluetoothAdapter through BluetoothManager.
final BluetoothManager bluetoothManager =
(BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
// Checks if Bluetooth is supported on the device.
if (mBluetoothAdapter == null) {
Toast.makeText(this,"error_bluetooth_not_supported", Toast.LENGTH_SHORT).show();
finish();
return;
}

// Ensures Bluetooth is enabled on the device.  If Bluetooth is not currently enabled,
// fire an intent to display a dialog asking the user to grant permission to enable it.
if (!mBluetoothAdapter.isEnabled()) {
if (!mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
}


2.3、扫描设备

1、首先实现扫描回调参数:mLeScanCallback

2、然后再调用 mBluetoothAdapter.stopLeScan(mLeScanCallback)

// Device scan callback.系统将扫描到的结果通过该回调方法的参数传递出来
private BluetoothAdapter.LeScanCallback  mLeScanCallback =
new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
//该线程用于更新UI
runOnUiThread(new Runnable() {
@Override
public void run() {
mLeDeviceListAdapter.addDevice(device);
mLeDeviceListAdapter.notifyDataSetChanged();
}
});
}
};

private void scanLeDevice(final boolean enable) {
if (enable) {
// Stops scanning after a pre-defined scan period.该段代码表示扫描10秒后停止,
// mhandler相当于计时10秒后执行停止扫描的操作
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);//即10秒后执行该语句
invalidateOptionsMenu();
}
}, SCAN_PERIOD);

mScanning = true;
mBluetoothAdapter.startLeScan(mLeScanCallback);
} else {
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
}
invalidateOptionsMenu();
}


2.4、建立连接

1、首先先实现中央回调参数:mGattCallback;

2、其次再实现mBluetoothGatt = device.connectGatt(this, false, mGattCallback);

private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
String intentAction;
if (newState == BluetoothProfile.STATE_CONNECTED) {
intentAction = ACTION_GATT_CONNECTED;
mConnectionState = STATE_CONNECTED;
broadcastUpdate(intentAction);
Log.i(TAG, "连接上了GATT服务器,Connected to GATT server.");
// Attempts to discover services after successful connection.
Log.i(TAG, "尝试开始发现服务,Attempting to start service discovery:" +
mBluetoothGatt.discoverServices());

} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
intentAction = ACTION_GATT_DISCONNECTED;
mConnectionState = STATE_DISCONNECTED;
Log.i(TAG, "不能从GATT服务器连接,Disconnected from GATT server.");
broadcastUpdate(intentAction);
}
}

@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
Log.w(TAG,"o
4000
nServicesDiscovered被系统回调,并广播出去");
} else {
Log.w(TAG, "onServicesDiscovered被系统回调,没有发现服务,不广播,status= " + status);
}
}

@Override
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
Log.w(TAG,"安卓系统回调onCharacteristicRead成功,并将数据广播出去");
}

@Override
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
Log.w(TAG,"回调onCharacteristicChanged,并将数据广播出去");
}

//当BluetoothGatt.writeCharacteristic(BluetoothGattCharacteristic)执行时,系统异步调用该回调方法
@Override
public void onCharacteristicWrite(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic,int status){
super.onCharacteristicWrite(gatt,characteristic,status);
if(status==BluetoothGatt.GATT_SUCCESS) {
Log.w(TAG,"回调了onCharacteristicWrite");
}
}
};

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
// parameter to false.
mBluetoothGatt = device.connectGatt(this, false, mGattCallback);//连接时,此处得到BluetoothGatt实例
Log.d(TAG, "Trying to create a new connection.");
mBluetoothDeviceAddress = address;//在连接当中传入设备地址到BluetoothService类中
mConnectionState = STATE_CONNECTING;
return true;
}


2.5、数据交互

1、输入数据,点击按钮将数据发送出去;

2、将数据绑定特定服务的特征,本案例中绑定的时UUID=”0000fff1-0000-1000-8000-00805f9b34fb”的这个特征

3、点击按钮后,中央将数据发送给了周边,周边会响应中央的请求

sendButton.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v){
String str=dateEditText.getText().toString().trim();
byte[] bytes=str.getBytes();
if (mConnected){
mBluetoothLeService.writeBle(bytes,
UUID.fromString("0000fff1-0000-1000-8000-00805f9b34fb"));
dateEditText.setText("");
Log.d(TAG,"点击发送按钮了");
}else {
Toast.makeText(DeviceControlActivity.this,"设备连接失败,请重连",Toast.LENGTH_SHORT).show();
}

private final ExpandableListView.OnChildClickListener servicesListClickListner =
new ExpandableListView.OnChildClickListener() {
@Override
public boolean onChildClick(ExpandableListView parent, View v, int groupPosition,
int childPosition, long id) {
if (mGattCharacteristics != null) {
final BluetoothGattCharacteristic characteristic =
mGattCharacteristics.get(groupPosition).get(childPosition);
final int charaProp = characteristic.getProperties();
if ((charaProp | BluetoothGattCharacteristic.PROPERTY_READ) > 0) {
// If there is an active notification on a characteristic, clear
// it first so it doesn't update the data field on the user interface.
if (mNotifyCharacteristic != null) {
mBluetoothLeService.setCharacteristicNotification(
mNotifyCharacteristic, false);
mNotifyCharacteristic = null;
}
mBluetoothLeService.readCharacteristic(characteristic);//此时异步调用回调方法onCharacteristicRead(),
// 在该回调方法中得到读取的结果数据,在该应用中,在BluetoothLeService中的该回调方法将结果广播出去,
// 然后在DeviceControlActivity的广播接收器中得到读取到的数据,并展示出来
}
if ((charaProp | BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0) {
mNotifyCharacteristic = characteristic;
mBluetoothLeService.setCharacteristicNotification(
characteristic, true);//通知安卓系统我要接受characristic这个特征的数据,true为接受,false为不接受
}

return true;
}
return false;
}
};


案例地址:https://github.com/lihongandroid/BleGattDemo.git
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android 蓝牙 BLE 中央
相关文章推荐