Неперехваченное исключение, созданное финализатором для повторного подключения Bluetooth в Android - java.io.IOExceptionAndroid

Форум для тех, кто программирует под Android
Ответить
Anonymous
 Неперехваченное исключение, созданное финализатором для повторного подключения Bluetooth в Android - java.io.IOException

Сообщение Anonymous »

Я пытаюсь работать с последовательным соединением Bluetooth, при котором я подключаюсь и общаюсь с устройством IOT последовательно через Bluetooth. Таким образом, устройство имеет переключатель включения/выключения, который может закрыть соединение Bluetooth при выключении устройства. Поэтому я пытаюсь добиться того, чтобы при включении устройства приложение автоматически обнаруживало устройство и автоматически подключалось к нему постоянно. Пока что мне удается добиться этого с помощью приведенного ниже кода.
К сожалению, пока не возникнет следующая ошибка. При возникновении этой ошибки приложение продолжает закрывать соединение все время после запроса соединения с устройством IOT.
Журнал ошибок:

Код: Выделить всё

2024-01-03 16:01:00.535  8401-8416  System                  com.mybluetooth.iot           E  Uncaught exception thrown by finalizer
2024-01-03 16:01:00.541  8401-8416  System                  com.mybluetooth.iot           E  java.io.IOException: socket not created
at android.net.LocalSocketImpl.shutdownInput(LocalSocketImpl.java:371)
at android.net.LocalSocket.shutdownInput(LocalSocket.java:238)
at android.bluetooth.BluetoothSocket.close(BluetoothSocket.java:780)
at android.bluetooth.BluetoothSocket.finalize(BluetoothSocket.java:371)
at java.lang.Daemons$FinalizerDaemon.doFinalize(Daemons.java:339)
at java.lang.Daemons$FinalizerDaemon.processReference(Daemons.java:324)
at java.lang.Daemons$FinalizerDaemon.runInternal(Daemons.java:300)
at java.lang.Daemons$Daemon.run(Daemons.java:145)
at java.lang.Thread.run(Thread.java:1012)
2024-01-03 16:01:00.541  8401-8416  System                  com.mybluetooth.iot           E  Uncaught exception thrown by finalizer
2024-01-03 16:01:00.541  8401-8416  System                  com.mybluetooth.iot           E  java.io.IOException: socket not created
at android.net.LocalSocketImpl.shutdownInput(LocalSocketImpl.java:371)
at android.net.LocalSocket.shutdownInput(LocalSocket.java:238)
at android.bluetooth.BluetoothSocket.close(BluetoothSocket.java:780)
at android.bluetooth.BluetoothSocket.finalize(BluetoothSocket.java:371)
at java.lang.Daemons$FinalizerDaemon.doFinalize(Daemons.java:339)
at java.lang.Daemons$FinalizerDaemon.processReference(Daemons.java:324)
at java.lang.Daemons$FinalizerDaemon.runInternal(Daemons.java:300)
at java.lang.Daemons$Daemon.run(Daemons.java:145)
at java.lang.Thread.run(Thread.java:1012)
2024-01-03 16:01:00.542  8401-8416  System                  com.mybluetooth.iot           E  Uncaught exception thrown by finalizer
2024-01-03 16:01:00.542  8401-8416  System                  com.mybluetooth.iot           E  java.io.IOException:  socket not created
at android.net.LocalSocketImpl.shutdownInput(LocalSocketImpl.java:371)
at android.net.LocalSocket.shutdownInput(LocalSocket.java:238)
at android.bluetooth.BluetoothSocket.close(BluetoothSocket.java:780)
at android.bluetooth.BluetoothSocket.finalize(BluetoothSocket.java:371)
at java.lang.Daemons$FinalizerDaemon.doFinalize(Daemons.java:339)
at java.lang.Daemons$FinalizerDaemon.processReference(Daemons.java:324)
at java.lang.Daemons$FinalizerDaemon.runInternal(Daemons.java:300)
at java.lang.Daemons$Daemon.run(Daemons.java:145)
at java.lang.Thread.run(Thread.java:1012)

**Error log for making Re-connect attempt after turning ON the IOT device**

2024-01-03 17:21:33.547 18742-18742 BaseActivity            com.mybluetooth.iot           E  Base Activity: This is ACL_DISCONNECTED
2024-01-03 17:21:33.572 18742-18742 BaseActivity            com.mybluetooth.iot           E  Base Activity: This is ACL_DISCONNECTED
2024-01-03 17:21:33.582 18742-18742 BaseActivity            com.mybluetooth.iot           E  Base Activity: This is ACL_DISCONNECTED
2024-01-03 17:21:33.591 18742-18742 BaseActivity            com.mybluetooth.iot           E  Base Activity: This is ACL_DISCONNECTED
2024-01-03 17:21:33.600 18742-18742 BaseActivity            com.mybluetooth.iot           E  Base Activity: This is ACL_DISCONNECTED
2024-01-03 17:21:33.606 18742-18742 BaseActivity            com.mybluetooth.iot           E  Base Activity: This is ACL_DISCONNECTED
2024-01-03 17:21:33.613 18742-18742 BaseActivity            com.mybluetooth.iot           E  Base Activity: This is ACL_DISCONNECTED
2024-01-03 17:21:33.626 18742-18742 BaseActivity            com.mybluetooth.iot           E  Base Activity: This is ACL_DISCONNECTED
2024-01-03 17:21:33.634 18742-18742 BaseActivity            com.mybluetooth.iot           E  Base Activity: This is ACL_DISCONNECTED
2024-01-03 17:21:33.643 18742-18742 BaseActivity            com.mybluetooth.iot           E  Base Activity: This is ACL_DISCONNECTED
2024-01-03 17:21:33.655 18742-18742 BaseActivity            com.mybluetooth.iot           E  Base Activity: This is ACL_DISCONNECTED
2024-01-03 17:21:34.273 18742-18742 BaseActivity            com.mybluetooth.iot           E  Base Activity: This is ACL_CONNECTED
2024-01-03 17:21:34.282 18742-18742 BaseActivity            com.mybluetooth.iot           E  Base Activity: This is ACL_CONNECTED
2024-01-03 17:21:34.282 18742-18742 BaseActivity            com.mybluetooth.iot           E  Base Activity: This is ACL_CONNECTED
2024-01-03 17:21:34.282 18742-18742 BaseActivity            com.mybluetooth.iot           E  Base Activity: This is ACL_CONNECTED
2024-01-03 17:21:34.282 18742-18742 BaseActivity            com.mybluetooth.iot           E  Base Activity: This is ACL_CONNECTED
2024-01-03 17:21:34.283 18742-18742 BaseActivity            com.mybluetooth.iot           E  Base Activity: This is ACL_CONNECTED
2024-01-03 17:21:34.284 18742-18742 BaseActivity            com.mybluetooth.iot           E  Base Activity: This is ACL_CONNECTED
2024-01-03 17:21:34.284 18742-18742 BaseActivity            com.mybluetooth.iot           E  Base Activity: This is ACL_CONNECTED
2024-01-03 17:21:34.284 18742-18742 BaseActivity            com.mybluetooth.iot           E  Base Activity: This is ACL_CONNECTED
2024-01-03 17:21:34.285 18742-18742 BaseActivity            com.mybluetooth.iot           E  Base Activity: This is ACL_CONNECTED
2024-01-03 17:21:34.285 18742-18742 BaseActivity            com.mybluetooth.iot           E  Base Activity: This is ACL_CONNECTED
2024-01-03 17:21:34.540 18742-18742 BaseActivity            com.mybluetooth.iot           E  Base Activity: Disconnected State
2024-01-03 17:21:34.560 18742-18742 BaseActivity            com.mybluetooth.iot           E  Base Activity:  This is ACL Event
2024-01-03 17:21:34.585 18742-18742 BaseActivity            com.mybluetooth.iot           E  Base Activity: Disconnected State
2024-01-03 17:21:34.611 18742-18742 BaseActivity            com.mybluetooth.iot           E  Base Activity: This is ACL Event
2024-01-03 17:21:34.612 18742-18742 BaseActivity            com.mybluetooth.iot           E  Base Activity: Connected
2024-01-03 17:21:34.612 18742-18742 DashboardA...........Kt com.mybluetooth.iot           E  :: This is for re-connected
2024-01-03 17:21:34.636 18742-18777 BT IO                   com.mybluetooth.iot           E  readByteArrayStream: Connection Disconnected from finally
2024-01-03 17:21:34.636 18742-18777 BT IO                   com.mybluetooth.iot           E  All Connections closed
BluetoothServiceProviderIO.kt

Код: Выделить всё

class BluetoothServiceProviderIO(val bluetoothSocket: BluetoothSocket?) {

private val inputStream: InputStream? = try {
bluetoothSocket?.inputStream
} catch (e: IOException) {
Log.e("BT IO", "Could not Open Input Stream")
e.printStackTrace()
throw SocketStreamException("Couldn't open InputStream socket")
}

private val outputStream: OutputStream? = try {
bluetoothSocket?.outputStream
} catch (e: IOException) {
Log.e("BT IO", "Could not Open OutputStream")
e.printStackTrace()
throw SocketStreamException("Couldn't open OutputStream socket")
}

/**
* Send array of bytes to bluetooth output stream.
*
* @param bytes data to send
* @return true if success, false if there was error occurred or disconnected
*/
fun send(data: ModelSendData): Boolean {
if (bluetoothSocket?.isConnected != true) return false

return try {
outputStream?.write(data.data)
outputStream?.flush()
true
} catch (e: IOException) {
e.printStackTrace()
false
}
}

@ExperimentalCoroutinesApi
fun readByteArrayStream(
delayMillis: Long = 10,
bufferCapacity: Int = 32
): Flow = channelFlow {

if (inputStream == null) {
Log.e("BT IO", "input Stream is null")
throw NullPointerException("inputStream is null. Perhaps bluetoothSocket is also null")
}

val buffer = ByteArray(bufferCapacity)
while (isActive) {
try {
if (inputStream.available() > 0) {
val numBytes = inputStream.read(buffer)
val readBytes = ByteArray(size = numBytes)
for (i in 0 until numBytes) {
readBytes[i] = buffer[i]
}
delay(delayMillis)
this.trySend(readBytes).isSuccess
}
} catch (e: IOException) {
Log.e("BT IO", "readByteArrayStream: Connection Disconnected from Catch")
closeConnections()
error("Couldn't read bytes from flow.  Disconnected")
} finally {
if (bluetoothSocket?.isConnected != true) {
Log.e("BT IO", "readByteArrayStream: Connection Disconnected from finally")
closeConnections()
break
}
}
}
}.flowOn(Dispatchers.IO)

/**
* Close the streams and socket connection.
*/
fun closeConnections() {
try {
inputStream?.close()
outputStream?.close()
bluetoothSocket?.close()
Log.e("BT IO", "All Connections closed")
} catch (e: Exception) {
Log.e("BT IO", "Connections close failed ${e.printStackTrace()}")
}
}
}
Bluetooth ServiceProvider.not

Код: Выделить всё

@SuppressLint("MissingPermission")
class BluetoothServiceProvider(private val context: Context) {

val bluetoothManager = context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager

@Volatile
var currentBluetoothSocket: BluetoothSocket? = null
private var bluetoothServiceProviderIO: BluetoothServiceProviderIO? = null

@SuppressLint("HardwareIds")
fun isBluetoothAvailable() =
!(bluetoothManager.adapter == null || TextUtils.isEmpty(bluetoothManager.adapter.address))

fun isBluetoothEnabled() = bluetoothManager.adapter.isEnabled

fun getIO(bluetoothSocket: BluetoothSocket): BluetoothServiceProviderIO {

if (bluetoothServiceProviderIO?.bluetoothSocket == bluetoothSocket) {
return bluetoothServiceProviderIO as BluetoothServiceProviderIO
}

currentBluetoothSocket = bluetoothSocket
bluetoothServiceProviderIO = BluetoothServiceProviderIO(bluetoothSocket)
return bluetoothServiceProviderIO as BluetoothServiceProviderIO
}

fun getIO(): BluetoothServiceProviderIO {
return getIO(currentBluetoothSocket!!)
}

@SuppressLint("MissingPermission")
fun enable() = bluetoothManager.adapter.isEnabled

fun disable() = !bluetoothManager.adapter.isEnabled

@SuppressLint("MissingPermission")
fun bondedDevices(): List = bluetoothManager.adapter.bondedDevices.toList()

fun startDiscovery() = bluetoothManager.adapter.startDiscovery()

fun isDiscovering() = bluetoothManager.adapter.isDiscovering

fun cancelDiscovery() = if (bluetoothManager.adapter.isDiscovering) {
bluetoothManager.adapter.cancelDiscovery()
true
} else {
false
}

@ExperimentalCoroutinesApi
fun discoverDevices(): Flow = callbackFlow {
val filter = IntentFilter(BluetoothDevice.ACTION_FOUND).apply {
addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED)
addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)
}
val receiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
when (intent?.action) {
BluetoothDevice.ACTION_FOUND -> {
val device =
intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE) as BluetoothDevice?
val rssi =
intent.getShortExtra(BluetoothDevice.EXTRA_RSSI, MIN_VALUE).toInt()
device?.let { trySend(BluetoothDeviceWrapper(it, rssi)).isSuccess }
}

BluetoothAdapter.ACTION_DISCOVERY_STARTED -> {
}

BluetoothAdapter.ACTION_DISCOVERY_FINISHED -> {
}
}
}
}
context.registerReceiver(receiver, filter)
awaitClose {
context.unregisterReceiver(receiver)
}
}.flowOn(Dispatchers.IO)

@ExperimentalCoroutinesApi
fun checkDiscoveryStatus(): Flow = callbackFlow  {
val filter = IntentFilter(BluetoothDevice.ACTION_FOUND).apply {
addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED)
addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)
}
val receiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
when (intent?.action) {
BluetoothDevice.ACTION_FOUND -> {
}

BluetoothAdapter.ACTION_DISCOVERY_STARTED -> {
trySend(BluetoothAdapter.ACTION_DISCOVERY_STARTED)
}

BluetoothAdapter.ACTION_DISCOVERY_FINISHED -> {
trySend(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)
}
}
}
}
context.registerReceiver(receiver, filter)
awaitClose {
context.unregisterReceiver(receiver)
}
}.flowOn(Dispatchers.IO)

@ExperimentalCoroutinesApi
fun getDeviceBondState(): Flow = callbackFlow {
val filter = IntentFilter().apply {
addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED)
}

val receiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
if (intent?.action == BluetoothDevice.ACTION_BOND_STATE_CHANGED) {
val mDevice: BluetoothDevice =
intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE)!!
//3 cases:
//case1: bonded already
if (mDevice.bondState == BluetoothDevice.BOND_BONDED) {
Log.e("BluetoothServiceProvider", "BroadcastReceiver: BOND_BONDED.")
}
//case2: creating a bond
if (mDevice.bondState == BluetoothDevice.BOND_BONDING) {
Log.e("BluetoothServiceProvider", "BroadcastReceiver: BOND_BONDING.")
}
//case3: breaking a bond
if (mDevice.bondState == BluetoothDevice.BOND_NONE) {
Log.e("BluetoothServiceProvider", "BroadcastReceiver: BOND_NONE.")
}
trySend(mDevice.bondState).isSuccess
}
}
}
context.registerReceiver(receiver, filter)
awaitClose {
context.unregisterReceiver(receiver)
}
}.flowOn(Dispatchers.IO)

fun connectToDevice(bluetoothDevice: BluetoothDevice,
uuid: UUID,
secure: Boolean = true): Deferred =
CoroutineScope(Dispatchers.IO).async {
val bluetoothSocket =
if (secure) bluetoothDevice.createRfcommSocketToServiceRecord(uuid)
else bluetoothDevice.createInsecureRfcommSocketToServiceRecord(uuid)
bluetoothSocket.apply {
currentBluetoothSocket = this@apply
connect()
}
}

@Throws(java.lang.Exception::class)
fun createBond(btDevice: BluetoothDevice?): Boolean {
val btClass = Class.forName("android.bluetooth.BluetoothDevice")
val createBondMethod = btClass.getMethod("createBond")
return createBondMethod.invoke(btDevice) as Boolean
}

@ExperimentalCoroutinesApi
fun aclEvents(): Flow = callbackFlow  {
val filter = IntentFilter().apply {
addAction(BluetoothDevice.ACTION_ACL_CONNECTED)
addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED)
addAction(BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED)
}
val receiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
intent?.let {
val device =
it.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE) as? BluetoothDevice
trySend(AclEvent(it.action ?: "", device)).isSuccess
}
}
}
context.registerReceiver(receiver, filter)
awaitClose {
context.unregisterReceiver(receiver)
}
}.flowOn(Dispatchers.IO)

fun closeConnections() = bluetoothServiceProviderIO?.closeConnections()
}
BTConnect.kt

Код: Выделить всё

class BTConnect(private val bluetoothServiceProvider: BluetoothServiceProvider) {

private val uuid: UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB")

@SuppressLint("MissingPermission")
fun connect(device: BluetoothDevice) = flow {
var state: BtConnection? = null
try {
bluetoothServiceProvider.connectToDevice(device, uuid, true).await()
bluetoothServiceProvider.currentBluetoothSocket.apply {
state = if (bluetoothServiceProvider.currentBluetoothSocket!!.isConnected) {
BtConnection.BtConnectedState(socket = bluetoothServiceProvider.currentBluetoothSocket!!)
} else {
BtConnection.BtDisconnectedState
}
}
} catch (e: IOException) {
state = BtConnection.BtDisconnectedState
} catch (e: Exception) {
state = BtConnection.BtDisconnectedState
Log.e("BT Connect", "connect: Failed other than IO Exception $e")
}
emit(state)
}
}
BaseActivity.kt

Код: Выделить всё

@OptIn(FlowPreview::class, ExperimentalCoroutinesApi::class)
class BaseActivity : AppCompatActivity() {

var connectionState = MutableLiveData()
private var progressDialog: CustomDialog? = null
lateinit var connectionStatus: Job

@Inject
lateinit var btConnect: BTConnect

@Inject
lateinit var bluetoothServiceProvider: BluetoothServiceProvider

@Inject
lateinit var preferenceHelper: PreferenceHelper

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
setContentView(layoutResId)
window.insetsController?.hide(WindowInsets.Type.statusBars())

MyApplication.component.inject(this)
}

@SuppressLint("MissingPermission")
override fun onResume() {
isScreenVisible = true
super.onResume()
}

@SuppressLint("MissingPermission", "SetTextI18n")
open fun checkForBondedDevices(): BluetoothDevice? {
var device: BluetoothDevice? = null
if (bluetoothServiceProvider.bondedDevices().isEmpty()) {
device = null
} else {
for (i in bluetoothServiceProvider.bondedDevices()) {
if ((i.name == preferenceHelper.deviceName) && (i.address == preferenceHelper.deviceAddress)) {
device = i
}
}
}
return device
}

open fun checkSendStatus(device: BluetoothDevice) {
lifecycleScope.launch {
if (isDeviceConnected) isDeviceConnected = false
withContext(Dispatchers.Main) {
while (!isDeviceConnected &&  isScreenVisible) {
btConnect.connect(device).safeCollect {
delay(200)
if (it != null) {
checkBtConnectionState(it)
}
return@safeCollect
}
}
}
}
}

@SuppressLint("MissingPermission")
open suspend fun checkBtConnectionState(btConnection: BtConnection) {
connectionState.postValue(btConnection)
when (btConnection) {
is BtConnection.BtConnectingLoadingState -> {
isDeviceConnected = false
showLog("Connecting Loading State")
}

is BtConnection.BtConnectedState -> {
isDeviceConnected = true
showLog("Connected")
if (!firstTimeNotConnectCheck) {
onDeviceConnected()
} else {
onDeviceReconnected()
}
startCommunicationWithDevice()
}

is BtConnection.BtErrorConnectingState -> {
isDeviceConnected = false
showLog("Connecting State")
}

is BtConnection.BtDisconnectedState -> {
isDeviceConnected = false
showLog("Disconnected State")
onDeviceDisconnected()
}
}
}

open fun checkConnectionStateOfPairedDevice(device: BluetoothDevice) {
connectionStatus = lifecycleScope.launch {
withContext(Dispatchers.Main) {
bluetoothServiceProvider.aclEvents().safeCollect {
when (it.action) {
BluetoothDevice.ACTION_ACL_CONNECTED -> {
isDeviceConnected = true
}

BluetoothDevice.ACTION_ACL_DISCONNECTED -> {
isDeviceConnected = false
checkSendStatus(checkForBondedDevices()!!)
}
}
}
}
}
}

@SuppressLint("MissingPermission")
open suspend fun startCommunicationWithDevice() {
bluetoothServiceProvider.readByteArrayStream().safeCollect {
if (it.isNotEmpty()) {
processReceivedBytesForResponse(it)
} else {
showLog("Data not received")
}
}
}

open fun processReceivedBytesForResponse(byteArray: ByteArray) {
try {
if (byteArray.isNotEmpty()) {
// Process data
}
} catch (e: Exception) {
showLog("From Processed Received Data: $e")
}
}

override fun onPause() {
bluetoothServiceProvider.closeConnections()
isScreenVisible = false
super.onPause()
}

private fun showLog(s: String) {
Log.e(tag, "Base Activity: $s")
}

open fun showToast(msg: String) {
if (msg.isNotEmpty()) Toast.makeText(this, msg, Toast.LENGTH_SHORT).show()
}

open fun showProgressDialog() {
progressDialog = CustomDialog(this)
progressDialog!!.setMessage("Please wait...")
progressDialog!!.setProgressStyle(ProgressDialog.STYLE_SPINNER)
progressDialog!!.isIndeterminate = true
progressDialog!!.setCancelable(false)
progressDialog!!.show()
}

open fun hideProgressDialog() {
if (progressDialog != null) {
progressDialog!!.dismiss()
}
}

override fun onWindowFocusChanged(hasFocus: Boolean) {
super.onWindowFocusChanged(hasFocus)
if (hasFocus) {
hideSystemUI()
}
}

abstract fun onDeviceConnected()
abstract fun onDeviceReconnected()
abstract fun onDeviceDisconnected()
}
Это полная реализация для установления и повторного установления соединения после перезапуска/включения устройства.
Это один из моих справочных кодов для разработки эту кодовую базу. https://github.com/ThanosFisherman/BlueFlow

Подробнее здесь: https://stackoverflow.com/questions/777 ... -android-j
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Android»