我有一个蓝牙耳机,它与我的Nexus 5X(运行Android 7.1)配对,我想连接到耳机的GATT服务器。我用以下代码尝试了它:
private BluetoothGattCallback btleGattCallback = new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
Log.d(TAG, "onConnectionStateChange: " + status + ", " + newState);
if(newState == STATE_CONNECTED) {
Log.d(TAG, "Device connected");
boolean ans = gatt.discoverServices();
Log.d(TAG, "Discover Services started: " + ans);
}
}
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
Log.d(TAG, "Number of Services: " + gatt.getServices().size());
}
};
public void onDeviceClicked(BluetoothDevice device) {
BluetoothGatt gatt = device.connectGatt(this, false, btleGattCallback);
Log.d(TAG, "Connected to GATT: " + gatt.connect());
}
如果我点击我的用户界面onDeviceClicked
中的耳机,则会调用此日志输出:
<!-- language: lang-none -->
Connected to GATT: true
onConnectionStateChange: 0, 2 // GATT_SUCCESS, STATE_CONNECTED
Device connected
Discover Services started: true
正如您所见,onServicesDiscovered
永远不会被解雇。我尝试使用connectGatt
(ref)致电TRANSPORT_LE
但我得到了onConnectionStateChange: 133, 0
。我还发现this question这就是为什么我添加了答案二中提到的gatt.connect()
方法。
你有什么想法我没有得到onServicesDiscovered
回调吗?
答案 0 :(得分:7)
Android上的BLE可能有点挑剔。
确保在UI线程上调用mBluetoothGatt.discoverServices()。
if(newState == STATE_CONNECTED) {
Log.d(TAG, "Device connected");
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
boolean ans = mBluetoothGatt.discoverServices();
Log.d(TAG, "Discover Services started: " + ans);
}
});
}
同时尝试将BluetoothGatt gatt
作为字段变量而不是局部变量。
如果您正在进行任何重要工作,请尝试使用掩盖所有特性的库,以便您可以专注于高级逻辑。 https://github.com/Polidea/RxAndroidBle
以下是如何阅读特征的示例。
connectionObservable
.flatMap(rxBleConnection -> rxBleConnection.readCharacteristic(characteristicUuid))
.observeOn(AndroidSchedulers.mainThread())
.subscribe(bytes -> {
readOutputView.setText(new String(bytes));
readHexOutputView.setText(HexString.bytesToHex(bytes));
writeInput.setText(HexString.bytesToHex(bytes));
}, this::onReadFailure);
或使用Java 7语法
connectionObservable
.flatMap(new Func1<RxBleConnection, Observable<byte[]>>() {
@Override
public Observable<byte[]> call(RxBleConnection rxBleConnection) {
return rxBleConnection.readCharacteristic(characteristicUuid);
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<byte[]>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
onReadFailure(e);
}
@Override
public void onNext(byte[] bytes) {
readOutputView.setText(new String(bytes));
readHexOutputView.setText(HexString.bytesToHex(bytes));
writeInput.setText(HexString.bytesToHex(bytes));
}
});
答案 1 :(得分:6)
对我来说真正有用的东西是在建立连接后等待大约600ms,然后开始服务发现。
答案 2 :(得分:0)
这可能会有所帮助
我将分两步解释:连接和发现服务
<强>连接强>: 从mainthread连接
将自动重新连接设置为false
如果Version大于或等于M,请设置Tranposrt类型
否则直接使用反射并正确处理
Handler(applicationContext.mainLooper).post {
Log.d(TAG, " Post is called inside mainlooper")
mBluetoothGatt = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
Log.d(TAG, " Is Or Greater than M $mBluetoothDevice")
mBluetoothDevice!!.connectGatt(this, false,
onGhattListener, TRANSPORT_LE)
} else {
Log.d(TAG, " Less than M")
try {
Log.d(TAG, " Trying TRANPORT LE with reflection")
val m = mBluetoothDevice!!.javaClass.getDeclaredMethod("connectGatt", Context::class.java, Boolean::class.javaPrimitiveType, BluetoothGattCallback::class.java, Int::class.javaPrimitiveType)
m.isAccessible = true
val transport = mBluetoothDevice!!.javaClass.getDeclaredField("TRANSPORT_LE").getInt(null)
m.invoke(mBluetoothDevice, this, false, onGhattListener, transport) as BluetoothGatt
} catch (e: Exception) {
e.printStackTrace()
Log.d(TAG, " Catch to call normal connection")
mBluetoothDevice!!.connectGatt(this, false,
onGhattListener)
}
}
Log.d(TAG, "mBluetooth gatt is $mBluetoothGatt")
mBluetoothGatt?.let {
refreshDeviceCache(mBluetoothGatt!!)
}
}
disover服务:在onGhattListener中,如果设备从主线程连接discoverServices()
override fun onConnectionStateChange(gatt: BluetoothGatt, status: Int,
newState: Int) {
Log.d(TAG, "onConnectionStateChange $gatt and status $status and newstate $newState")
when (newState) {
BluetoothGatt.STATE_CONNECTED -> {
Handler(Looper.getMainLooper()).post {
gatt.discoverServices()
}
}
BluetoothGatt.STATE_DISCONNECTED -> {
}
BluetoothGatt.STATE_CONNECTING -> {
}
BluetoothGatt.STATE_DISCONNECTING -> {
}
}
}
这可能会解决您的问题
使用反射调用刷新方法
fun refreshDeviceCache(gatt: BluetoothGatt): Boolean {
try {
val localMethod = gatt.javaClass.getMethod("refresh")
if (localMethod != null) {
return localMethod.invoke(gatt) as Boolean
}
} catch (localException: Exception) {
Log.e(TAG, "An exception occured while refreshing device")
localException.printStackTrace()
}
return false
}
答案 3 :(得分:0)
实际上,我通过多次执行mBluetoothGatt.discoverServices()方法(10次以上)来解决此问题,
int i = 10;
while (i > 0)
{
if (!mIsBLE_Finded) //如果服务发现失败,继续执行discoverServices方法
{
i--;
mBluetoothGatt.discoverServices();
System.out.println("BLEService-->" + "尝试次数:" + i);
}
else //在10次的尝试中,存在某次服务发现成功了
{
i = -1;
}
}
答案 4 :(得分:0)
有同样的问题,但仅等待600毫秒是不够的。这可能是由于使用了BLE模块。我通过调用方法解决了问题
discoverServices();
致电后
device.connectGatt(this,false,gattCallback)
我基本上只是每5秒钟调用一次DiscoverServices(这是任意选择的)
private void discoverServices() {
if(!gattConnected) { //just a boolean
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
gatt.discoverServices();
}
});
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
@Override
public void run() {
discoverServices();
}
}, 5000);
}
}
在我的gattCallback的onServicesDiscovered(...)方法中,将gattConnected设置为true。 这对我有用。
答案 5 :(得分:0)
我也遇到了同样的问题。
在 onStart()
方法中开始扫描。它对我有用
之前我开始对 onCreate
方法进行扫描。这就是为什么它对我不起作用