微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Kotlin 的协程如何帮助我们处理低功耗蓝牙

如何解决Kotlin 的协程如何帮助我们处理低功耗蓝牙

我在主要活动(导航组件)中使用低功耗蓝牙

Ble:每 10 秒对 BEACON 附近的目标进行扫描。

问题是扫描和连接信标应用程序的性能很慢。

希望协程能解决这个问题,Kotlin 的协程如何帮助我们处理 BLE 扫描和回调?

代码

import android.annotation.TargetApi
import android.bluetooth.*
import android.bluetooth.BluetoothAdapter.LeScanCallback
import android.bluetooth.le.*
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.util.Log
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import java.util.*

@TargetApi(21)
class MainActivityScan : AppCompatActivity() {
    private var mBluetoothAdapter: BluetoothAdapter? = null
    private val REQUEST_ENABLE_BT = 1
    private var mHandler: Handler? = null
    private var mLEScanner: BluetoothLeScanner? = null
    private var settings: ScanSettings? = null
    private var filters: List<ScanFilter>? = null
    private var mGatt: BluetoothGatt? = null
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        mHandler = Handler()
        if (!packageManager.hasSystemFeature(PackageManager.FEATURE_BLUetoOTH_LE)) {
            Toast.makeText(this,"BLE Not Supported",Toast.LENGTH_SHORT).show()
            finish()
        }
        val bluetoothManager = getSystemService(BLUetoOTH_SERVICE) as BluetoothManager
        mBluetoothAdapter = bluetoothManager.adapter
    }

    override fun onResume() {
        super.onResume()
        if (mBluetoothAdapter == null || !mBluetoothAdapter!!.isEnabled) {
            val enableBtIntent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)
            startActivityForResult(enableBtIntent,REQUEST_ENABLE_BT)
        } else {
            if (Build.VERSION.SDK_INT >= 21) {
                mLEScanner = mBluetoothAdapter!!.bluetoothLeScanner
                settings = ScanSettings.Builder()
                        .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
                        .build()
                filters = ArrayList()
            }
            scanLeDevice(true)
        }
    }

    override fun onPause() {
        super.onPause()
        if (mBluetoothAdapter != null && mBluetoothAdapter!!.isEnabled) {
            scanLeDevice(false)
        }
    }

    override fun onDestroy() {
        if (mGatt == null) {
            return
        }
        mGatt!!.close()
        mGatt = null
        super.onDestroy()
    }

    override fun onActivityResult(requestCode: Int,resultCode: Int,data: Intent?) {
        if (requestCode == REQUEST_ENABLE_BT) {
            if (resultCode == RESULT_CANCELED) {
                //Bluetooth not enabled.
                finish()
                return
            }
        }
        super.onActivityResult(requestCode,resultCode,data)
    }

    private fun scanLeDevice(enable: Boolean) {
        if (enable) {
            mHandler!!.postDelayed({
                if (Build.VERSION.SDK_INT < 21) {
                    mBluetoothAdapter!!.stopLeScan(mLeScanCallback)
                } else {
                    mLEScanner!!.stopScan(mScanCallback)
                }
            },SCAN_PERIOD)
            if (Build.VERSION.SDK_INT < 21) {
                mBluetoothAdapter!!.startLeScan(mLeScanCallback)
            } else {
                mLEScanner!!.startScan(filters,settings,mScanCallback)
            }
        } else {
            if (Build.VERSION.SDK_INT < 21) {
                mBluetoothAdapter!!.stopLeScan(mLeScanCallback)
            } else {
                mLEScanner!!.stopScan(mScanCallback)
            }
        }
    }

    private val mScanCallback: ScanCallback = object : ScanCallback() {
        override fun onScanResult(callbackType: Int,result: ScanResult) {
            Log.i("callbackType",callbackType.toString())
            Log.i("result",result.toString())
            val btDevice = result.device
            connectToDevice(btDevice)
        }

        override fun onBatchScanResults(results: List<ScanResult>) {
            for (sr in results) {
                Log.i("ScanResult - Results",sr.toString())
            }
        }

        override fun onScanFailed(errorCode: Int) {
            Log.e("Scan Failed","Error Code: $errorCode")
        }
    }
    private val mLeScanCallback = LeScanCallback { device,RSSi,scanRecord ->
        runOnUiThread {
            Log.i("onLeScan",device.toString())
            connectToDevice(device)
        }
    }

    fun connectToDevice(device: BluetoothDevice) {
        if (mGatt == null) {
            mGatt = device.connectGatt(this,false,gattCallback)
            scanLeDevice(false) // will stop after first device detection
        }
    }

    private val gattCallback: BluetoothGattCallback = object : BluetoothGattCallback() {
        override fun onConnectionStateChange(gatt: BluetoothGatt,status: Int,newState: Int) {
            Log.i("onConnectionStateChange","Status: $status")
            when (newState) {
                BluetoothProfile.STATE_CONNECTED -> {
                    Log.i("gattCallback","STATE_CONNECTED")
                    gatt.discoverServices()
                }
                BluetoothProfile.STATE_disCONNECTED -> Log.e("gattCallback","STATE_disCONNECTED")
                else -> Log.e("gattCallback","STATE_OTHER")
            }
        }

        override fun onServicesdiscovered(gatt: BluetoothGatt,status: Int) {
            val services = gatt.services
            Log.i("onServicesdiscovered",services.toString())
            gatt.readCharacteristic(services[1].characteristics[0])
        }

        override fun onCharacteristicRead(gatt: BluetoothGatt,characteristic: BluetoothGattCharacteristic,status: Int) {
            Log.i("onCharacteristicRead",characteristic.toString())
            gatt.disconnect()
        }
    }

    companion object {
        private const val SCAN_PERIOD: Long = 10000
    }
}

解决方法

您应该尝试将扫描部分移至 IO 线程,这可能有助于提高性能。还有这个库:https://github.com/NordicSemiconductor/Android-BLE-Library 是 BLE 应用的绝佳选择

如果您打算为此使用协程,您可以使用流对扫描逻辑进行建模,即 flowOn(Dispatchers.IO),并使用来自 Kotlin 的 Flow

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。