Android BluetoothGatt在活动更改时变为空

时间:2016-01-19 08:02:00

标签: android bluetooth-lowenergy android-bluetooth

我正在开发一个Android应用程序,它要求我将数据发送到蓝牙低功耗设备。连接事件成功后,我收到回叫消息后,我想更改活动并显示新的GUI在哪里切换点击我想将数据发送到连接的设备。问题是在活动发生变化后我的BluetoothGatt变为null并且BluetoothGattCharacteristic也变为null并且我无法发送数据。我该如何解决这个问题?下面是我的代码主类,onResume调用连接活动并连接到第一个可用设备,连接成功后接收回调消息并更改活动。

public class MainActivity extends Activity implements BluetoothLeUart.Callback {
public TextView messages;   
private BluetoothLeUart uart;

  public void writeLine(final CharSequence text) {
    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            messages.append(text);
            messages.append("\n");
                        }
    });
}

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    messages = (TextView) findViewById(R.id.messages);

    // Initialize UART.
    uart = new BluetoothLeUart(getApplicationContext());
    messages.setMovementMethod(new ScrollingMovementMethod());
}


@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
}

@Override
protected void onResume() {
    super.onResume();
    writeLine("Scanning for devices ...");
    uart.registerCallback(this);
    uart.connectFirstAvailable();

}

@Override
protected void onStop() {
    super.onStop();
    uart.unregisterCallback(this);
    uart.disconnect();

}

@Override
public boolean onOptionsItemSelected(MenuItem item) {

    int id = item.getItemId();
    if (id == R.id.action_settings) {
        return true;
    }
    return super.onOptionsItemSelected(item);
}

// UART Callback event handlers.



// UART Callback event handlers.
@Override
public void onConnected(BluetoothLeUart uart) {
    // Called when UART device is connected and ready to send/receive data.
    //messages.append("connected2");
    writeLine("Connected!");
    Intent intent = new Intent(MainActivity.this,SwitchClass.class);
    startActivity(intent);
}
}

这是我的代码BluetoothLeUart类,它执行连接活动并提供回调消息。

    public class BluetoothLeUart extends BluetoothGattCallback implements BluetoothAdapter.LeScanCallback {
    // UUIDs for UART service and associated characteristics.
    public static UUID UART_UUID = UUID.fromString("6E400001-B5A3-F393-E0A9-E50E24DCCA9E");
    public static UUID TX_UUID   = UUID.fromString("6E400002-B5A3-F393-E0A9-E50E24DCCA9E");
    public static UUID RX_UUID   = UUID.fromString("6E400003-B5A3-F393-E0A9-E50E24DCCA9E");

    // UUID for the UART BTLE client characteristic which is necessary for notifications.
    public static UUID CLIENT_UUID = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");

    // UUIDs for the Device Information service and associated characeristics.
    public static UUID DIS_UUID       = UUID.fromString("0000180a-0000-1000-8000-00805f9b34fb");
    public static UUID DIS_MANUF_UUID = UUID.fromString("00002a29-0000-1000-8000-00805f9b34fb");
    public static UUID DIS_MODEL_UUID = UUID.fromString("00002a24-0000-1000-8000-00805f9b34fb");
    public static UUID DIS_HWREV_UUID = UUID.fromString("00002a26-0000-1000-8000-00805f9b34fb");
    public static UUID DIS_SWREV_UUID = UUID.fromString("00002a28-0000-1000-8000-00805f9b34fb");

    // Internal UART state.
    private Context context;
    private WeakHashMap<Callback, Object> callbacks;
    private BluetoothAdapter adapter;
    private BluetoothGatt gatt;
    private BluetoothGattCharacteristic tx;
    private BluetoothGattCharacteristic rx;
    private boolean connectFirst;
    private boolean writeInProgress; // Flag to indicate a write is currently in progress



    // Queues for characteristic read (synchronous)
    private Queue<BluetoothGattCharacteristic> readQueue;

    // Interface for a BluetoothLeUart client to be notified of UART actions.
    public interface Callback {
        public void onConnected(BluetoothLeUart uart);
        public void onConnectFailed(BluetoothLeUart uart);
        public void onDisconnected(BluetoothLeUart uart);
        public void onReceive(BluetoothLeUart uart, BluetoothGattCharacteristic rx);
        public void onDeviceFound(BluetoothDevice device);
        public void onDeviceInfoAvailable();
    }

    public BluetoothLeUart(Context context) {
        super();
        this.context = context;
        this.callbacks = new WeakHashMap<Callback, Object>();
        this.adapter = BluetoothAdapter.getDefaultAdapter();
        this.gatt = null;
        this.tx = null;
        this.rx = null;
        this.disManuf = null;
        this.disModel = null;
        this.disHWRev = null;
        this.disSWRev = null;
        this.disAvailable = false;
        this.connectFirst = false;
        this.writeInProgress = false;
        this.readQueue = new ConcurrentLinkedQueue<BluetoothGattCharacteristic>();
    }


     // Send data to connected UART device.
    public void sendbyte(byte[] data) {
        if (tx == null || data == null || data.length == 0) {
            // Do nothing if there is no connection or message to send.
            return;
        }
        // Update TX characteristic value.  Note the setValue overload that takes a byte array must be used.
        tx.setValue(data);
        writeInProgress = true; // Set the write in progress flag
        gatt.writeCharacteristic(tx);
        // ToDo: Update to include a timeout in case this goes into the weeds
        while (writeInProgress); // Wait for the flag to clear in onCharacteristicWrite

        gatt.readCharacteristic(rx);
    }

    // Send data to connected UART device.
    public void send(String data) {
        if (data != null && !data.isEmpty()) {
            sendbyte(data.getBytes(Charset.forName("UTF-8")));
        }
    }

    // Register the specified callback to receive UART callbacks.
    public void registerCallback(Callback callback) {
        callbacks.put(callback, null);
    }

    // Unregister the specified callback.
    public void unregisterCallback(Callback callback) {
        callbacks.remove(callback);
    }

    // Disconnect to a device if currently connected.
    public void disconnect() {
        if (gatt != null) {
            gatt.disconnect();
        }
        gatt = null;
        tx = null;
        rx = null;
    }

    // Stop any in progress UART device scan.
    public void stopScan() {
        if (adapter != null) {
            adapter.stopLeScan(this);
        }
    }

    // Start scanning for BLE UART devices.  Registered callback's onDeviceFound method will be called
    // when devices are found during scanning.
    public void startScan() {
        if (adapter != null) {
            adapter.startLeScan(this);
        }
    }

    // Connect to the first available UART device.
    public void connectFirstAvailable() {
        // Disconnect to any connected device.
        disconnect();
        // Stop any in progress device scan.
        stopScan();
        // Start scan and connect to first available device.
        connectFirst = true;
        startScan();
    }

    // Handlers for BluetoothGatt and LeScan events.
    @Override
    public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
        super.onConnectionStateChange(gatt, status, newState);
        if (newState == BluetoothGatt.STATE_CONNECTED) {
            if (status == BluetoothGatt.GATT_SUCCESS) {
                // Connected to device, start discovering services.
                if (!gatt.discoverServices()) {
                    // Error starting service discovery.
                    connectFailure();
                }
                else {
                    notifyOnConnected(this);
                }
            }
            else {
                // Error connecting to device.
                connectFailure();
            }
        }
        else if (newState == BluetoothGatt.STATE_DISCONNECTED) {
            // Disconnected, notify callbacks of disconnection.
            rx = null;
            tx = null;
            notifyOnDisconnected(this);
        }
    }

    @Override
    public void onServicesDiscovered(BluetoothGatt gatt, int status) {
        super.onServicesDiscovered(gatt, status);
        // Notify connection failure if service discovery failed.
        if (status == BluetoothGatt.GATT_FAILURE) {
            connectFailure();
            return;
        }

        // Save reference to each UART characteristic.
        tx = gatt.getService(UART_UUID).getCharacteristic(TX_UUID);
        rx = gatt.getService(UART_UUID).getCharacteristic(RX_UUID);

        // Save reference to each DIS characteristic.
        disManuf = gatt.getService(DIS_UUID).getCharacteristic(DIS_MANUF_UUID);
        disModel = gatt.getService(DIS_UUID).getCharacteristic(DIS_MODEL_UUID);
        disHWRev = gatt.getService(DIS_UUID).getCharacteristic(DIS_HWREV_UUID);
        disSWRev = gatt.getService(DIS_UUID).getCharacteristic(DIS_SWREV_UUID);

        // Add device information characteristics to the read queue
        // These need to be queued because we have to wait for the response to the first
        // read request before a second one can be processed (which makes you wonder why they
        // implemented this with async logic to begin with???)
        readQueue.offer(disManuf);
        readQueue.offer(disModel);
        readQueue.offer(disHWRev);
        readQueue.offer(disSWRev);

        // Request a dummy read to get the device information queue going
      //  gatt.readCharacteristic(disManuf);

        // Setup notifications on RX characteristic changes (i.e. data received).
        // First call setCharacteristicNotification to enable notification.
        if (!gatt.setCharacteristicNotification(rx, true)) {
            // Stop if the characteristic notification setup failed.
            connectFailure();
            return;
        }
        // Next update the RX characteristic's client descriptor to enable notifications.
        BluetoothGattDescriptor desc = rx.getDescriptor(CLIENT_UUID);
        if (desc == null) {
            // Stop if the RX characteristic has no client descriptor.
            connectFailure();
            return;
        }
        desc.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
        if (!gatt.writeDescriptor(desc)) {
            // Stop if the client descriptor could not be written.
            connectFailure();
            return;
        }
        // Notify of connection completion.
        notifyOnConnected(this);
    }

    @Override
    public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
        super.onCharacteristicChanged(gatt, characteristic);
        notifyOnReceive(this, characteristic);
    }

    @Override
    public void onCharacteristicRead (BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
        super.onCharacteristicRead(gatt, characteristic, status);

        if (status == BluetoothGatt.GATT_SUCCESS) {
            //Log.w("DIS", characteristic.getStringValue(0));
            // Check if there is anything left in the queue
            BluetoothGattCharacteristic nextRequest = readQueue.poll();
            if(nextRequest != null){
                // Send a read request for the next item in the queue
               // gatt.readCharacteristic(nextRequest);
            }
            else {
                // We've reached the end of the queue
                disAvailable = true;
               // notifyOnDeviceInfoAvailable();
            }
        }
        else {
            //Log.w("DIS", "Failed reading characteristic " + characteristic.getUuid().toString());
        }
    }

    @Override
    public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
        super.onCharacteristicWrite(gatt, characteristic, status);

        if (status == BluetoothGatt.GATT_SUCCESS) {
            // Log.d(TAG,"Characteristic write successful");
        }
        writeInProgress = false;
    }

    @Override
    public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
        // Stop if the device doesn't have the UART service.
        if (!parseUUIDs(scanRecord).contains(UART_UUID)) {
            //main.writeLine("Parse UUID failed...");
            //main.messages.append("Parse UUID failed...");
            return;

        }


        // Connect to first found device if required.
        if (connectFirst) {
            // Stop scanning for devices.
            stopScan();
            // Prevent connections to future found devices.
            connectFirst = false;
            // Connect to device.
            gatt = device.connectGatt(context, true, this);
        }
    }

    // Private functions to simplify the notification of all callbacks of a certain event.
    private void notifyOnConnected(BluetoothLeUart uart) {
        for (Callback cb : callbacks.keySet()) {
            if (cb != null) {
                cb.onConnected(uart);
            }
        }
    }

    private List<UUID> parseUUIDs(final byte[] advertisedData) {
        List<UUID> uuids = new ArrayList<UUID>();

        int offset = 0;
        while (offset < (advertisedData.length - 2)) {
            int len = advertisedData[offset++];
            if (len == 0)
                break;

           // main.writeLine(advertisedData.toString());
            int type = advertisedData[offset++];
            switch (type) {
                case 0x02: // Partial list of 16-bit UUIDs
                case 0x03: // Complete list of 16-bit UUIDs
                    //main.writeLine("case 02,03...");
                   // main.messages.append("case 02,03...");
                    while (len > 1) {
                        int uuid16 = advertisedData[offset++];
                        uuid16 += (advertisedData[offset++] << 8);
                        len -= 2;
                        uuids.add(UUID.fromString(String.format("%08x-0000-1000-8000-00805f9b34fb", uuid16)));
                    }
                    break;

                case 0x06:// Partial list of 128-bit UUIDs
                case 0x07:// Complete list of 128-bit UUIDs
                    // Loop through the advertised 128-bit UUID's.
                    //main.writeLine("case 06,07...");
                   // main.messages.append("case 06,07...");
                    while (len >= 16) {
                        try {
                            // Wrap the advertised bits and order them.
                            ByteBuffer buffer = ByteBuffer.wrap(advertisedData, offset++, 16).order(ByteOrder.LITTLE_ENDIAN);
                            long mostSignificantBit = buffer.getLong();
                            long leastSignificantBit = buffer.getLong();
                            uuids.add(new UUID(leastSignificantBit,
                                    mostSignificantBit));
                        } catch (IndexOutOfBoundsException e) {
                            // Defensive programming.
                            //Log.e(LOG_TAG, e.toString());
                            continue;
                        } finally {
                            // Move the offset to read the next uuid.
                            offset += 15;
                            len -= 16;
                        }
                    }
                    break;
                default:
                    //main.writeLine("case default...");
                  //  main.messages.append("case default");
                    offset += (len - 1);
                    break;
            }
        }
        return uuids;
    }
}

这是我发送数据的课程

public class SwitchClass extends Activity {
public TextView messages;
public Switch Switch1;
public byte[] switchData = {'U','1','1','1','0','0','2','Z'};
private BluetoothLeUart uart;   

public void writeLine(final CharSequence text) {
    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            messages.append(text);
            messages.append("\n");
            //messages.setText("anirudh");
        }
    });
}

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.switchlayout);

    Switch1 = (Switch) findViewById(R.id.switch1);
     uart = new BluetoothLeUart(getApplicationContext());

     Switch1.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
        @Override
        public void onCheckedChanged(CompoundButton buttonView,
                                     boolean isChecked) {
            if (isChecked) {
               switchString = new String(switchData);
            writeLine(switchString);
            // send this array 8 bytes to BLE
            sendData(switchString);
            }
        }
    });

    public void sendData(String sendVal) {
    StringBuilder stringBuilder = new StringBuilder();
    stringBuilder.append(sendVal.toCharArray(), 0, 8);
    uart.send(stringBuilder.toString());
}

4 个答案:

答案 0 :(得分:0)

您正在通过此活动创建服务,并且您正在销毁 onStop 因此,您的服务现已断开连接,因此您无法自动获取 bluetoothgatt 适配器

我建议你在你的活动中设置一个子片段,这样你的服务就会保持活力,你可以拥有尽可能多的片段来展示它!

希望这会对你有所帮助!!

答案 1 :(得分:0)

您可以访问https://github.com/captain-miao/bleYan,这是一个简单的BLE库和示例。

答案 2 :(得分:0)

我也得到了和你一样的错误。在我的情况下,我在onServiceDiscover方法下注释掉或删除了以下行。它突然起作用。它可能不是答案,希望它会给你一些线索来解决。

    disManuf = gatt.getService(DIS_UUID).getCharacteristic(DIS_MANUF_UUID);
    disModel = gatt.getService(DIS_UUID).getCharacteristic(DIS_MODEL_UUID);
    disHWRev = gatt.getService(DIS_UUID).getCharacteristic(DIS_HWREV_UUID);
    disSWRev = gatt.getService(DIS_UUID).getCharacteristic(DIS_SWREV_UUID);

    readQueue.offer(disManuf);
    readQueue.offer(disModel);
    readQueue.offer(disHWRev);
    readQueue.offer(disSWRev);

答案 3 :(得分:0)

您必须设置为同步BluetoothGatt对象,例如

public void setBluetoothGatt(BluetoothGatt gatt) {
    synchronized (this) {
        this.bluetoothGatt = gatt;
    }
}

因为更改活动时BluetoothGatt引发DeadObject异常