kotlin - 在 Kotlin 中获取 BLE 设备
问题描述
我SettingsActivity
允许用户从配对的蓝牙设备列表中进行选择。
但是,蓝牙低功耗似乎发生了一些奇怪的事情,设备无法正常配对:我尝试连接的设备不会与我的任何 android 设备配对,而且我注意到我的 Fitbit 不是t 是我手机上配对设备的列表,即使它似乎可以正常工作。怎么回事?
无论如何,问题是:如何将 BLE 设备列表添加到正确设备列表中?
(我查看了https://developer.android.com/guide/topics/connectivity/bluetooth-le#find但它只是一些杂乱无章的无法解释的代码;它没有说明将它们放在哪里,如何调用它们,或者它们如何组合在一起,如果我复制它,就会出现大量错误。)
class SettingsActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// get bluetooth devices
var btDevices: Array<CharSequence> = arrayOf("")
try {
val bt: BluetoothManager =
getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager;
val bta: BluetoothAdapter = bt.adapter;
// Get normal Bluetooth devices.
val pairedDevices: Set<BluetoothDevice> = bta.bondedDevices
// Get Bluetooth Low Energy devices.
// HOW?!
btDevices = pairedDevices.map { z -> z.name }.toTypedArray()
}
catch(e:Exception) {}
// Start the fragment
setContentView(R.layout.settings_activity)
supportFragmentManager
.beginTransaction()
.replace(R.id.settings, SettingsFragment(cs))
.commit()
supportActionBar?.setDisplayHomeAsUpEnabled(true)
// Slap the toolbar.
val toolbar = findViewById<Toolbar>(R.id.settings_toolbar) // Must be after setContentView or else it returns null.
setSupportActionBar(toolbar)
toolbar.setNavigationOnClickListener(object : View.OnClickListener {
override fun onClick(v: View?) {
finish()
}
})
}
class SettingsFragment(adapters: Array<CharSequence>) : PreferenceFragmentCompat() {
private var adapters: Array<CharSequence> = adapters
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.root_preferences, rootKey)
val p:ListPreference? = findPreference<ListPreference>("bluetoothName")
p?.setEntries(adapters)
p?.setEntryValues(adapters)
}
}
}
解决方案
我确信这是非常错误的,但它似乎确实有效。
它的诀窍是将引用添加到PreferenceFragment
公共方法以更新列表,然后将引用传递PreferencesFragment
给 theScanCallback
以便它可以将其更新的列表发送到首选项。
package com.rwb.psamfd
import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothDevice
import android.bluetooth.BluetoothManager
import android.bluetooth.le.ScanCallback
import android.bluetooth.le.ScanResult
import android.content.Context
import android.os.Build
import android.os.Bundle
import android.util.Log
import android.view.View
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
import androidx.preference.ListPreference
import androidx.preference.PreferenceFragmentCompat
class SettingsActivity : AppCompatActivity() {
private val bleScanCallback = @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
object : ScanCallback(){
public var settings:SettingsFragment? = null;
override fun onScanResult(callbackType: Int, result: ScanResult?) {
super.onScanResult(callbackType, result)
Log.d(
"DeviceListActivity",
"onScanResult: ${result?.device?.address} - ${result?.device?.name}"
)
if (result?.device?.name != null && !btAdapters.contains(result?.device?.name!!)) {
btAdapters.add(result?.device?.name!!)
}
settings?.updateAdapters(btAdapters)
}
override fun onBatchScanResults(results: MutableList<ScanResult>?) {
super.onBatchScanResults(results)
Log.d("DeviceListActivity","onBatchScanResults:${results.toString()}")
if(results != null){
for(result:ScanResult in results!!)
{
if(result.device?.name != null && !btAdapters.contains(result.device?.name!! ))
{
btAdapters.add(result.device?.name!! )
}
}
settings?.updateAdapters(btAdapters)
}
}
override fun onScanFailed(errorCode: Int) {
super.onScanFailed(errorCode)
Log.d("DeviceListActivity", "onScanFailed: $errorCode")
}
}
private lateinit var btm : BluetoothManager
private lateinit var bta: BluetoothAdapter
// This is initialised from paired normal Bluetooth, then added to by BLE.
// BLE has a reference to the preferences fragment on which it calles the update method when new devices are found.
private val btAdapters: ArrayList<String> = ArrayList<String>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
btm = getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager;
bta = btm.adapter
// get bluetooth devices
try {
// Normal Bluetooth.
for(p:BluetoothDevice in bta.bondedDevices)
{
if(p.name != null) {
btAdapters.add(p.name)
}
}
// Bluetooth Low Energy done in onResume and onPause.
}
catch(e:Exception) {}
// Start the fragment
val sf:SettingsFragment = SettingsFragment(btAdapters)
setContentView(R.layout.settings_activity)
supportFragmentManager
.beginTransaction()
.replace(R.id.settings, sf)
.commit()
supportActionBar?.setDisplayHomeAsUpEnabled(true)
// Connect the SettingsFragment to the ScanCallback.
bleScanCallback.settings = sf
// Slap the toolbar.
val toolbar = findViewById<Toolbar>(R.id.settings_toolbar) // Must be after setContentView or else it returns null.
setSupportActionBar(toolbar)
toolbar.setNavigationOnClickListener(object : View.OnClickListener {
override fun onClick(v: View?) {
finish()
}
})
}
override fun onResume() {
super.onResume()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
bta.bluetoothLeScanner.startScan(bleScanCallback)
}
}
override fun onPause() {
super.onPause()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
bta.bluetoothLeScanner.stopScan(bleScanCallback)
}
}
class SettingsFragment(btAdapters: ArrayList<String>) : PreferenceFragmentCompat() {
private var btAdapters: Array<CharSequence> = btAdapters.map{z -> z as CharSequence}.toTypedArray()
private lateinit var btPreference : ListPreference
fun updateAdapters(newBtAdapters: ArrayList<String>){
btAdapters = newBtAdapters.map{z -> z as CharSequence}.toTypedArray()
btPreference.setEntries(btAdapters)
btPreference.setEntryValues(btAdapters)
}
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.root_preferences, rootKey)
btPreference = findPreference<ListPreference>("bluetoothName")!!
btPreference.setEntries(btAdapters)
btPreference.setEntryValues(btAdapters)
}
}
}
推荐阅读
- sql - Will Merge Into table_x always invalidate package or SP when adding new column to table_x?
- angular - Does DI in Angular concern any external resource?
- wso2 - How to set password policy expiration time in WSO2 IS
- php - 无法从 PDO 中的函数获取数据到 ajax
- ruby-on-rails - Updated to Rails 4.0, getting error: no implicit conversion of Symbol into Integer
- java - Getting error while working with configuring data source in spring boot
- java - 使用 JFileChooser 返回路径
- python - 想要在openxx中为一个特定的post请求禁用CSRF
- r - 从数据框中子集一列,将子集保留为数据框
- css - 在 css.erb 文件中使用 ruby 语法。更改显示在打印预览部分,但在 pdf 打印 css 中不起作用