#android #kotlin #android-fragments #bluetooth #bluetooth-lowenergy
Вопрос:
В течение нескольких дней я пытаюсь реализовать подключение BLE в своем приложении. Я делаю это во второстепенном фрагменте, а не в основном. Но когда я сканирую, чтобы найти устройство BLE (с помощью startScan ( leScanCallback
)), оно никогда не переходит в метод обратного leScanCallback
вызова . Я следовал некоторым инструкциям, но не могу понять, почему это не работает.
Вот моя основная активность.kt
package com.example.start
class MainActivity : AppCompatActivity() {
private lateinit var drawerLayout: DrawerLayout
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main)
drawerLayout = binding.drawerLayout
val navController = this.findNavController(R.id.myNavHostFragment)
NavigationUI.setupActionBarWithNavController(this, navController, drawerLayout) //link the navigation controller amp; drawer layout to the app bar
NavigationUI.setupWithNavController(binding.navView, navController) //allows the user to display the navigation drawer
//PERMISSION
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
if (ContextCompat.checkSelfPermission(baseContext,
Manifest.permission.ACCESS_BACKGROUND_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
val PERMISSION_CODE = 0 //Should be >= 0
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.ACCESS_BACKGROUND_LOCATION),
PERMISSION_CODE)
}
}
//==========================Bluetooth Part==========================================
val REQUEST_ENABLE_BT : Int = 1 //Will stock the result of enabling the bluetooth
//RESULT_OK = -1 (0xffffffff)
//RESULT_CANCELLED = 0 (0x00000000)
//val bluetoothAdapter: BluetoothAdapter? = BluetoothAdapter.getDefaultAdapter()
val bluetoothAdapter: BluetoothAdapter by lazy {
val bluetoothManager = getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
bluetoothManager.adapter
}
if (bluetoothAdapter == null) {
// Device doesn't support Bluetooth
}
if (bluetoothAdapter?.isEnabled == false) { //If bluetooth is disable, we active it
val enableBtIntent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT)
}
}
}
А вот мой файл ConnectFragment.kt, где я нажимаю кнопку «btnScan», чтобы начать исследование
package com.example.start
private const val SELECT_DEVICE_REQUEST_CODE = 0
class ConnectFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
//return inflater.inflate(R.layout.fragment_connect, container, false)
val binding = DataBindingUtil.inflate<FragmentConnectBinding>(
inflater, R.layout.fragment_connect, container, false
)
binding.btnScan.setOnClickListener {
view : View ->
scanLeDevice()
}
return binding.root
}
private val bluetoothLeScanner: BluetoothLeScanner
get() {
val bluetoothManager = requireContext().getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
val bluetoothAdapter = bluetoothManager.adapter
return bluetoothAdapter.bluetoothLeScanner
}
// Device scan callback.
private val leScanCallback = object : ScanCallback() {
override fun onScanResult(callbackType: Int, result: ScanResult) {
super.onScanResult(callbackType, result)
//TODO TEST TEST TEST
Log.d("ScanDeviceActivity", "leScanCallback >>")
Log.d("ScanDeviceActivity", "onScanResult(): ${result?.device?.address} - ${result?.device?.name}")
}
override fun onBatchScanResults(results: MutableList<ScanResult>?) {
super.onBatchScanResults(results)
Log.d("DeviceListActivity","onBatchScanResults:${results.toString()}")
}
override fun onScanFailed(errorCode: Int) {
super.onScanFailed(errorCode)
Log.d("DeviceListActivity", "onScanFailed: $errorCode")
}
}
private var scanning = false
private val handler = Handler()
// Stops scanning after 10 seconds.
private val SCAN_PERIOD: Long = 10000
fun scanLeDevice() {
if (!scanning) { // Stops scanning after a pre-defined scan period.
handler.postDelayed({
scanning = false
bluetoothLeScanner.stopScan(leScanCallback)
}, SCAN_PERIOD)
scanning = true
//PERMISSION COARSE LOCATION
Log.d("ScanDeviceStart", "startScan()")
when (PermissionChecker.checkSelfPermission(requireContext(), Manifest.permission.ACCESS_COARSE_LOCATION)) {
PackageManager.PERMISSION_GRANTED -> bluetoothLeScanner.startScan(leScanCallback)
else -> requestPermissions(arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION), 1)
}
} else {
scanning = false
bluetoothLeScanner.stopScan(leScanCallback)
}
}
//Permission
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
when (requestCode) {
1 -> when (grantResults) {
intArrayOf(PackageManager.PERMISSION_GRANTED) -> {
Log.d("ScanDevices", "onRequestPermissionsResult(PERMISSION_GRANTED)")
bluetoothLeScanner.startScan(leScanCallback)
}
else -> {
Log.d("ScanDevices", "onRequestPermissionsResult(not PERMISSION_GRANTED)")
}
}
else -> super.onRequestPermissionsResult(requestCode, permissions, grantResults)
}
}
}
После того, как я нажал свою кнопку, консоль отладки заканчивается:
D/Bluetooth-сканер: Остановите сканирование с помощью обратного вызова
Комментарии:
1. Я предлагаю проверить, работает ли этот пример на вашем устройстве, и изменить его в соответствии с вашими целями: проект BLEProof на github — 2 приложения, центральные и периферийные, весь код в MainActivity.kt
2. Мне удалось заставить его работать с вашим решением. Я полностью заменил свой код тем, который вы дали. Спасибо
3. Сыворотку вы используете
Handler
вместоCoroutines
?