前台服务重启后多次接收BluetoothGattCallback

时间:2019-06-18 05:32:26

标签: android bluetooth-lowenergy

我正在使用支持BLE的硬件,并使用Android的Foreground Service与该硬件进行通信。 前台服务负责处理BLE相关事件,并且在一段时间内按照要求运行良好,但是由于某种原因,如果前台服务被杀死或BLE连接断开,则应用会尝试再次重新连接到BLE,然后BLE回调开始从BluetoothGattCallback获取重复事件,即使硬件将单个事件发送到Bluetooth,但Android BluetoothGattCallback接收到相同的多个回调,这在我们的实现中导致很多错误。

作为参考,请按以下方式浏览日志

Following are methods and callbacks from my foreground service,

BLEManagerService: *****onDescriptorWrite: 0*****<br>
BLEManagerService: *****onDescriptorWrite: 0*****<br>
BLEManagerService: *****onDescriptorWrite: 0*****<br>
BLEManagerService: Firmware: onCharacteristicRead true<br>
BLEManagerService: *****onDescriptorWrite: 0*****<br>
BLEManagerService: Firmware: onCharacteristicRead true<br>
BLEManagerService: *****onCharacteristicRead: 0*****<br>
BLEManagerService: *****onCharacteristicRead: 0*****<br>

override fun onCreate() {
    super.onCreate()

    mBluetoothGatt?.let { refreshDeviceCache(it) }

    registerReceiver(btStateBroadcastReceiver, IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED))
}

    /**
 * Start BLE scan
 */
private fun scanLeDevice(enable: Boolean) {
    if (enable && bleConnectionState == DISCONNECTED) {
        //initialize scanning BLE
        startScan()
        scanTimer = scanTimer()
    } else {
        stopScan("scanLeDevice: (Enable: $enable)")
    }
}

private fun scanTimer(): CountDownTimer {
    return object : CountDownTimer(SCAN_PERIOD, 1000) {
        override fun onTick(millisUntilFinished: Long) {
            //Nothing to do

        }

        override fun onFinish() {
            if (SCAN_PERIOD > 10000 && bleConnectionState == DISCONNECTED) {
                stopScan("restart scanTimer")
                Thread.sleep(200)
                scanLeDevice(true)
                SCAN_PERIOD -= 5000
                if (null != scanTimer) {
                    scanTimer!!.cancel()
                    scanTimer = null
                }
                scanTimer = scanTimer()
            } else {
                stopScan("stop scanTimer")
                SCAN_PERIOD = 60000
            }
        }
    }
}


//Scan callbacks for more that LOLLIPOP versions
private val mScanCallback = object : ScanCallback() {
    override fun onScanResult(callbackType: Int, result: ScanResult) {
        val btDevice = result.device
        if (null != btDevice) {
            val scannedDeviceName: String? = btDevice.name

            scannedDeviceName?.let {
                if (it == mBluetoothFemurDeviceName) {
                    stopScan("ScanCallback: Found device")
                    //Disconnect from current connection if any
                    mBluetoothGatt?.let {it1 ->
                        it1.close()
                        mBluetoothGatt = null
                    }
                    connectToDevice(btDevice)
                }
            }
        }
    }

    override fun onBatchScanResults(results: List<ScanResult>) {
        //Not Required
    }

    override fun onScanFailed(errorCode: Int) {
        Log.e(TAG, "*****onScanFailed->Error Code: $errorCode*****")
    }
}

/**
 * Connect to BLE device
 * @param device
 */
fun connectToDevice(device: BluetoothDevice) {
    scanLeDevice(false)// will stop after first device detection

    //Stop Scanning before connect attempt
    try {
        if (null != scanTimer) {
            scanTimer!!.cancel()
        }
    } catch (e: Exception) {
        //Just handle exception if something
        // goes wrong while canceling the scan timer
    }
    //Stop scan if still BLE scanner is running
    stopScan("connectToDevice")
    if (mBluetoothGatt == null) {
        connectedDevice = device
        if (Build.VERSION.SDK_INT >= 26)
            connectedDevice?.connectGatt(this, false, mGattCallback)
    }else{
        disconnectDevice()
        connectedDevice = device
        connectedDevice?.connectGatt(this, false, mGattCallback)
    }
}

/**
 * Disconnect from BLE device
 */
private fun disconnectDevice() {
    mBluetoothGatt?.close()
    mBluetoothGatt = null

    bleConnectionState = DISCONNECTED
    mBluetoothManager = null
    mBluetoothAdapter = null
    mBluetoothFemurDeviceName = null
    mBluetoothTibiaDeviceName = null
    connectedDevice = null
}

/****************************************
 * BLE Related Callbacks starts         *
 * Implements callback methods for GATT *
 ****************************************/
// Implements callback methods for GATT events that the app cares about.  For example,
// connection change and services discovered.
private val mGattCallback = object : BluetoothGattCallback() {

    /**
     * Connection state changed callback
     */
    override fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) {
        if (newState == BluetoothProfile.STATE_CONNECTED) {
            mBluetoothGatt = gatt                
            //Stop Scanning before connect attempt
            try {
                if (null != scanTimer) {
                    scanTimer!!.cancel()
                }
            } catch (e: Exception) {
                //Just handle exception if something
                // goes wrong while canceling the scan timer
            }
            stopScan("onConnectionStateChange")// will stop after first device detection

        } else if (newState == BluetoothProfile.STATE_DISCONNECTED || status == 8) {

            disconnectDevice()
            Handler(Looper.getMainLooper()).postDelayed({
                initialize()
            }, 500)

        }
    }

    /**
     * On services discovered
     * @param gatt
     * @param status
     */
    override fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) {
        super.onServicesDiscovered(gatt, status)

    }

    override fun onDescriptorWrite(gatt: BluetoothGatt, descriptor: BluetoothGattDescriptor, status: Int) {
        super.onDescriptorWrite(gatt, descriptor, status)

    }

    /**
     * On characteristic read operation complete
     * @param gatt
     * @param characteristic
     * @param status
     */
    override fun onCharacteristicRead(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, status: Int) {
        super.onCharacteristicRead(gatt, characteristic, status)

    }

    /**
     * On characteristic write operation complete
     * @param gatt
     * @param characteristic
     * @param status
     */
    override fun onCharacteristicWrite(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, status: Int) {
        super.onCharacteristicWrite(gatt, characteristic, status)
        val data = characteristic.value
        val dataHex = byteToHexStringJava(data)
    }

    /**
     * On Notification/Data received from the characteristic
     * @param gatt
     * @param characteristic
     */
    override fun onCharacteristicChanged(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic) {
        super.onCharacteristicChanged(gatt, characteristic)
        val data = characteristic.value
        val dataHex = byteToHexStringJava(data)


    }

    override fun onReadRemoteRssi(gatt: BluetoothGatt, rssi: Int, status: Int) {
        super.onReadRemoteRssi(gatt, rssi, status)
        val b = Bundle()
        b.putInt(BT_RSSI_VALUE_READ, rssi)
        receiver?.send(APP_RESULT_CODE_BT_RSSI, b)
    }
}


/**
 * Bluetooth state receiver to handle the ON/OFF states
 */
private val btStateBroadcastReceiver = object : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        val state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1)

        when (state) {

            BluetoothAdapter.STATE_OFF -> {
                //STATE OFF
            }

            BluetoothAdapter.STATE_ON -> {
                //STATE ON
                btState = BT_ON
                val b = Bundle()
                receiver?.send(APP_RESULT_CODE_BT_ON, b)
                initialize()
            }

            BluetoothAdapter.STATE_TURNING_OFF -> {
                //Not Required

            }

            BluetoothAdapter.STATE_TURNING_ON -> {
                //Not Required

            }
        }
    }
}

private fun handleBleDisconnectedState() {
    mBluetoothGatt?.let {
        it.close()

        receiver?.send(DISCONNECTED, b)
        Handler(Looper.getMainLooper()).postDelayed({
            mBluetoothManager = null
            mBluetoothAdapter = null
            mBluetoothFemurDeviceName = null
            mBluetoothTibiaDeviceName = null

            mBluetoothGatt = null
        }, 1000)
    }
}


/****************************************
 * BLE Related Callbacks End  ***
 ****************************************/

/****************************************************
 * Register Receivers to handle calbacks to UI    ***
 ****************************************************/

override fun onDestroy() {
    super.onDestroy()

    try {
        mBluetoothGatt?.let {
            it.close()
            mBluetoothGatt = null
        }
        unregisterReceivers()
        scanTimer?.cancel()

    } catch (e: Exception) {
        e.printStackTrace()
    }
}

override fun onTaskRemoved(rootIntent: Intent?) {
    super.onTaskRemoved(rootIntent)
    Log.e(TAG, "onTaskRemoved")
    stopSelf()
}

/**
 * Unregister the receivers before destroying the service
 */
private fun unregisterReceivers() {
    unregisterReceiver(btStateBroadcastReceiver)
}

companion object {
    private val TAG = BLEManagerService::class.java.simpleName
    private var mBluetoothGatt: BluetoothGatt? = null
    var bleConnectionState: Int = DISCONNECTED
}

}

1 个答案:

答案 0 :(得分:2)

不要在onConnectionStateChange中设置mBluetoothGatt = gatt。而是根据connectGatt的返回值进行设置。否则,您可能会创建多个BluetoothGatt对象而不关闭先前的对象,因此会得到多个回调。