我正在开发一个可连接到adafruitflora BLE设备以接收信息的应用程序。我希望该应用程序显示找到的设备的列表,当单击列表视图中的项目时,建立连接并可以接收数据。最终,我想将所说的数据带到另一个活动中,以便实时绘制图形(如果可能)。有一些我不了解的事情,希望有人能为您提供启示。
onPause
和onResume
使列表视图出现故障(显示设备,然后将其删除)import android.annotation.SuppressLint;
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.BluetoothProfile;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
import android.content.Intent;
import android.os.Build;
import android.os.ParcelUuid;
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.Button;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import no.nordicsemi.android.support.v18.scanner.BluetoothLeScannerCompat;
import no.nordicsemi.android.support.v18.scanner.ScanFilter;
import no.nordicsemi.android.support.v18.scanner.ScanResult;
import no.nordicsemi.android.support.v18.scanner.ScanSettings;
public class BluetoothDiscovery extends AppCompatActivity {
private String TAG = "Bluetooth Device";
private int REQUEST_ENABLE_BT = 5;
private BluetoothAdapter mBluetoothAdapter;
private BluetoothLeScannerCompat scanner;
private ScanSettings settings;
private UUID baseUUID = UUID.fromString("6e400001-b5a3-f393-e0a9-e50e24dcca9e"); // service UUID
private UUID txUUID = UUID.fromString("6e400002-b5a3-f393-e0a9-e50e24dcca9e"); // TX UUID characteristic
private UUID rxUUID = UUID.fromString("6e400003-b5a3-f393-e0a9-e50e24dcca9e"); // RX UUID characteristic
private ScanFilter scanFilter;
private BluetoothDevice device, mdevice;
private BluetoothGatt mGatt;
private boolean mScanning = false;
private ArrayList<deviceShowFormat> foundDevices = new ArrayList<>();
formattingAdapter BTadapter;
Button scanButton;
TextView fancyWords;
ListView deviceList;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_bluetooth_discovery);
mBluetoothAdapter.getDefaultAdapter();
scanButton = findViewById(R.id.scanButt);
scanButton.setText(getString(R.string.notScanning));
fancyWords = findViewById(R.id.discoverText);
fancyWords.setText(getString(R.string.nonScanTitle));
deviceList = findViewById(R.id.deviceList);
BTadapter = new formattingAdapter(BluetoothDiscovery.this, foundDevices);
deviceList.setAdapter(BTadapter);
scanner = BluetoothLeScannerCompat.getScanner();
settings = new ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_BALANCED).setReportDelay(500).build();
scanFilter = new ScanFilter.Builder().setServiceUuid(new ParcelUuid(baseUUID)).build();
//scanner.startScan(Arrays.asList(scanFilter), settings, mScanCallback);
deviceList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@SuppressLint("LongLogTag")
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
deviceShowFormat mBTDevice = foundDevices.get(i);
BluetoothDevice Device = mBTDevice.get_device();
String deviceName = mBTDevice.get_device_name();
String deviceAddress = mBTDevice.get_device_address();
Log.d(TAG, "Selected device: " + Device.toString());
Log.d(TAG, "Selected device name: " + deviceName);
Log.d(TAG, "Selected device address: " + deviceAddress);
//BluetoothDevice deviceConnect = mBluetoothAdapter.getRemoteDevice(deviceAddress);
//deviceConnect.createBond();
mGatt = Device.connectGatt(BluetoothDiscovery.this, false, mGattCallback);
Toast.makeText(BluetoothDiscovery.this, "Selected device: " + deviceName, Toast.LENGTH_SHORT).show();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
Device.createBond();
}
Log.d(TAG, "" + Device.getBondState());
if(Device.getBondState() == BluetoothDevice.BOND_BONDED){
Toast.makeText(BluetoothDiscovery.this, "Bluetooth device connected successfully", Toast.LENGTH_SHORT).show();
}
mGatt.getServices();
mGatt.getConnectedDevices();
Log.d("THIS IS THE DEVICES UUID", String.valueOf(Device.getUuids()));
Log.d("DEVICE SERVICES", String.valueOf(mGatt.getServices()));
}
});
}
private final no.nordicsemi.android.support.v18.scanner.ScanCallback mScanCallback = new no.nordicsemi.android.support.v18.scanner.ScanCallback() {
@Override
public void onScanResult(int callbackType, ScanResult result) {
super.onScanResult(callbackType, result);
Log.i("onScanResult", "device detected");
device = result.getDevice();
String deviceName = device.getName();
String deviceAddress = device.getAddress();
Log.d(TAG, "Scanned device: " + device.toString());
Log.d(TAG, "Scanned device name: " + deviceName);
Log.d(TAG, "Scanned device address: " + deviceAddress);
foundDevices.add(new deviceShowFormat(device, deviceName, deviceAddress));
BTadapter.notifyDataSetChanged();
}
};
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
super.onConnectionStateChange(gatt, status, newState);
Log.i("onConnectionStateChange", "State Changed from: " + status + " to " + newState);
if (newState == BluetoothProfile.STATE_CONNECTED){
Toast.makeText(BluetoothDiscovery.this, "Attempting service discovery", Toast.LENGTH_SHORT).show();
Log.i("onConnectionStateChange", "Attempting service discovery: " + gatt.discoverServices());
gatt.discoverServices();
} else if (newState == BluetoothProfile.STATE_DISCONNECTED){
Toast.makeText(BluetoothDiscovery.this, "Connection has been terminated", Toast.LENGTH_SHORT).show();
}
}
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status){
super.onServicesDiscovered(gatt, status);
Log.i("onServicesDiscovered", "Hey, we found a service");
if (status != BluetoothGatt.GATT_SUCCESS){
// Handle error
Log.d("onServicesDiscovered" , "" + status);
return;
}
BluetoothGattCharacteristic characteristic = gatt.getService(baseUUID).getCharacteristic(rxUUID);
gatt.setCharacteristicNotification(characteristic, true);
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(txUUID);
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
gatt.writeDescriptor(descriptor);
}
@Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status){
Log.i("onCharacteristicRead", "Characteristic has been read");
readCounterCharacteristic(characteristic);
}
@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
if (mGatt.writeCharacteristic(characteristic)){
Log.d("Characteristic changed", "Possibly looking for a write");
}
if (mGatt.readCharacteristic(characteristic)){
readCounterCharacteristic(characteristic);
}
}
private void readCounterCharacteristic(BluetoothGattCharacteristic characteristic){
if (mGatt.readCharacteristic(characteristic)){
byte[] data = characteristic.getValue();
Log.d("READ DATA", data.toString());
}
// if (rxUUID.equals(characteristic.getUuid())){
// //byte[] data = characteristic.getValue();
// byte[] data = mGatt.readCharacteristic(characteristic);
// //int value = Ints.fromByteArray(data);
// Log.d("READ DATA", data.toString());
// }
}
};
public void toggleScan(View view){
mScanning = !mScanning;
if(mScanning){
scanner.startScan(mScanCallback); //Arrays.asList(scanFilter) null, settings,
scanButton.setText(getString(R.string.scanInProgress));
fancyWords.setText(getString(R.string.ScanTitle));
} else {
scanner.stopScan(mScanCallback);
scanButton.setText(getString(R.string.notScanning));
}
}
// @Override
// public void onPause(){
// super.onPause();
//
//// if(mScanning){
//// mScanning = !mScanning;
// scanner.stopScan(mScanCallback);
//// }
//
// //Empty Adapter
// //BTadapter.clear();
// //BTadapter.notifyDataSetChanged();
//
// //mdevice = device;
//
// }
//
// @Override
// public void onResume(){
// super.onResume();
//
// if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
// Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
// startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
// }
//
// //device = mdevice;
// }
}
代码是我应用程序中的第二个活动,在第一个蓝牙中初始化了,什么都没有。上面的代码有效,但是我没有从设备接收任何数据,并且不确定其是否真正连接。从代码中显示的日志中我得到:
使用以下资源:
https://github.com/NordicSemiconductor/Android-Scanner-Compat-Library
https://learn.adafruit.com/introducing-the-adafruit-bluefruit-le-uart-friend/uart-service
答案 0 :(得分:0)
您错过了初始化mBluetoothAdapter
截至(在oncreate时):
BluetoothManager manager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = manager.getAdapter();
代替:
mBluetoothAdapter.getDefaultAdapter();
初始化变量并准备使用它之后,只需检查是否需要RuntimePermissions即可使用蓝牙。
答案 1 :(得分:0)
android BLE通信中的很多东西都是异步的。
因此,当您调用Device.connectGatt()时,需要等待onConnectionStateChange回调再执行下一步。您尝试枚举服务的尝试将失败(可能很安静),因为此时连接状态尚未从0变为2。在您的日志中,您可以看到在调用getServices()来回叫连接状态已变为connected之前,已经进行了调用。
让事情变得棘手,以我的经验,您应该只从主线程进行BluetoothDevice交互。 (编辑:显然不是必须从主线程发送请求)
因此,您执行的每个命令(连接,读取特征值,写入,断开连接,枚举服务等)都应类似于:
轻描淡写:在Objective-C和react-native-ble-plx中这要容易得多,因为它们可以为您处理线程。如果您设计一种从一开始就将结果从回调线程传递到主线程的好方法,那么您将省去很多麻烦。
用于将内容返回到UI线程的示例代码:
Handler m_handler;
public void onResume() {
m_handler = new Handler(); // creates a Handler bound to the UI thread, which lets us fire messages back and forth between threads.
}
// ... other stuff ...
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
super.onConnectionStateChange(gatt, status, newState);
Log.i("onConnectionStateChange", "State Changed from: " + status + " to " + newState);
if (newState == BluetoothProfile.STATE_CONNECTED){
// oh boy, we're connected. Let's try to discover services!
// m_handler.post() is a good way to make sure the thing you pass runs on the UI thread.
m_handler.post(new Runnable() {
@Override
public void run() {
gatt.discoverServices();
}
})
}
}
答案 2 :(得分:0)
对于将来需要查找此文件的任何人:如果收到类似于D / BluetoothGatt的消息:onConnectionUpdated()-设备= xx:xx:xx:xx:xx:xx:xx间隔= 6延迟= 0超时= 500状态= 0,您正在连接到设备,但“不足”以接收信息。对我来说,事实证明我必须单击设备才能第二次连接才能实际接收数据。我不知道为什么
答案 3 :(得分:0)
您的答案
For anyone looking this up in the future: If you receive a message similar to D/BluetoothGatt: onConnectionUpdated() - Device=xx:xx:xx:xx:xx:xx interval=6 latency=0 timeout=500 status=0 you are connecting to the device but not "enough" to recieve info. For me it turned out i had to click the device to connect to a second time to actually recieve the data. I dont know why yet
我很不幸遇到了这个问题,您可以在我的问题中看到 BLE onDescriptorWrite is not trigger when writeDescriptor receive true 您说的是第二点击设备,您的应用或其他ble设备。 非常感谢。