Получение BluetoothGattCallback несколько раз после перезапуска службы переднего плана - PullRequest
4 голосов
/ 18 июня 2019

Я работаю с оборудованием с поддержкой BLE и общаюсь с ним с помощью Foreground Service на Android.Служба Foreground отвечает за обработку событий, связанных с BLE, и некоторое время работает достаточно хорошо, как того требуют требования, но каким-то образом, если служба Foreground прерывается или соединение 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 Ответ

2 голосов
/ 02 июля 2019

Не устанавливайте mBluetoothGatt = gatt в onConnectionStateChange.Вместо этого установите его из возвращаемого значения connectGatt.В противном случае вы можете создать несколько объектов BluetoothGatt без закрытия предыдущих и, следовательно, получить несколько обратных вызовов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...