CoroutineWorker 中的实时数据观察器
Live data observer inside CoroutineWorker
我有一个定期执行的 Worker。它连接到 BLE 设备并从中同步数据。连接由观察者完成。 doWork 调用 syncRides()。 syncRides 创建了一个 observeForever,并在建立连接时启动连接 BleClient.runBleSync() 调用。
我担心的是每 15 分钟(最短 WorkManager 时间)调用一次的“observeForever”并创建未删除的 observeForever。问题是 BleWorker 没有用于创建“BleClient.connectionStatus.observe”而不是“BleClient.connectionStatus.observeForever”的 LifecycleOwner。我的问题是我是否应该关注使用 observeForever 并每 15 分钟触发一次。或者您可以建议更好的选择,例如添加和删除观察者。
此外,当 运行ning 没有 GlobalScope.launch(Dispatchers.Main) 时,会出现此函数无法在后台线程上 运行 的错误。那么Dispatchers.Main在Worker中运行ning是什么意思呢?
class BleWorker(appContext: Context, workerParams: WorkerParameters) : CoroutineWorker(appContext, workerParams) {
override suspend fun doWork(): Result {
return try {
try {
RLog.d("Run work manager")
syncRides()
val output: Data = workDataOf("KEY_RESULT" to 1)
Result.success(output)
} catch (e: Exception) {
RLog.d("exception in doWork ${e.message}")
Result.failure()
}
} catch (e: Exception) {
RLog.d("exception in doWork ${e.message}")
Result.failure()
}
}
private suspend fun syncRides() {
GlobalScope.launch(Dispatchers.Main) {
val bleDevice = SharedPreferenceHelper.getBleMac()
if (bleDevice != null && BleClient.connectionStatus.value == BleClient.ConnectionStatus.NOT_CONNECTED) {
BleClient.connect(bleDevice)
}
BleClient.connectionStatus.observeForever {
RLog.d("Observing $it")
when (it) {
BleClient.ConnectionStatus.CONNECTED -> {
GlobalScope.launch(Dispatchers.IO) {
RLog.d("Running sync")
BleClient.runBleSync()
}
}
else -> {
RLog.d("No status")
}
}
}
}
}
BleClient:
object BleClient {
val connectionStatus = MutableLiveData(ConnectionStatus.NOT_CONNECTED)
fun connect(mac: String) {
//do some magic
connectionStatus.postValue(ConnectionStatus.CONNECTED)
}
}
我假设该应用通过蓝牙连接到另一台设备的任何同步数据。如果我的假设是正确的,首先,您应该将同步过程卸载到前台服务,因为该过程需要很长时间。您仍然可以使用 WorkManager 进行调度。在前台服务中,您应该连接 BLE 并同步数据。为此,有不同的选择。如果你需要使用 observable 来观察连接状态,你应该使用 MutableSharedFlow 而不是 MutableLiveData 这样你就可以观察你在服务 class 中创建的生命周期范围的变化。但是,在我看来,更好的做法是将 connect() 函数转换为可挂起函数。为此,您可以使用 suspendCoroutine 构建器进行转换。此外,如果您同时从不同线程调用 connect 函数,则必须使用锁来避免多重连接。 Kotlin 协程为此提供了非阻塞锁。将 connect() 函数转换为挂起函数后,您可以以线性方式实现您的逻辑,这很简单,不需要任何类型的观察。
我有一个定期执行的 Worker。它连接到 BLE 设备并从中同步数据。连接由观察者完成。 doWork 调用 syncRides()。 syncRides 创建了一个 observeForever,并在建立连接时启动连接 BleClient.runBleSync() 调用。
我担心的是每 15 分钟(最短 WorkManager 时间)调用一次的“observeForever”并创建未删除的 observeForever。问题是 BleWorker 没有用于创建“BleClient.connectionStatus.observe”而不是“BleClient.connectionStatus.observeForever”的 LifecycleOwner。我的问题是我是否应该关注使用 observeForever 并每 15 分钟触发一次。或者您可以建议更好的选择,例如添加和删除观察者。
此外,当 运行ning 没有 GlobalScope.launch(Dispatchers.Main) 时,会出现此函数无法在后台线程上 运行 的错误。那么Dispatchers.Main在Worker中运行ning是什么意思呢?
class BleWorker(appContext: Context, workerParams: WorkerParameters) : CoroutineWorker(appContext, workerParams) {
override suspend fun doWork(): Result {
return try {
try {
RLog.d("Run work manager")
syncRides()
val output: Data = workDataOf("KEY_RESULT" to 1)
Result.success(output)
} catch (e: Exception) {
RLog.d("exception in doWork ${e.message}")
Result.failure()
}
} catch (e: Exception) {
RLog.d("exception in doWork ${e.message}")
Result.failure()
}
}
private suspend fun syncRides() {
GlobalScope.launch(Dispatchers.Main) {
val bleDevice = SharedPreferenceHelper.getBleMac()
if (bleDevice != null && BleClient.connectionStatus.value == BleClient.ConnectionStatus.NOT_CONNECTED) {
BleClient.connect(bleDevice)
}
BleClient.connectionStatus.observeForever {
RLog.d("Observing $it")
when (it) {
BleClient.ConnectionStatus.CONNECTED -> {
GlobalScope.launch(Dispatchers.IO) {
RLog.d("Running sync")
BleClient.runBleSync()
}
}
else -> {
RLog.d("No status")
}
}
}
}
}
BleClient:
object BleClient {
val connectionStatus = MutableLiveData(ConnectionStatus.NOT_CONNECTED)
fun connect(mac: String) {
//do some magic
connectionStatus.postValue(ConnectionStatus.CONNECTED)
}
}
我假设该应用通过蓝牙连接到另一台设备的任何同步数据。如果我的假设是正确的,首先,您应该将同步过程卸载到前台服务,因为该过程需要很长时间。您仍然可以使用 WorkManager 进行调度。在前台服务中,您应该连接 BLE 并同步数据。为此,有不同的选择。如果你需要使用 observable 来观察连接状态,你应该使用 MutableSharedFlow 而不是 MutableLiveData 这样你就可以观察你在服务 class 中创建的生命周期范围的变化。但是,在我看来,更好的做法是将 connect() 函数转换为可挂起函数。为此,您可以使用 suspendCoroutine 构建器进行转换。此外,如果您同时从不同线程调用 connect 函数,则必须使用锁来避免多重连接。 Kotlin 协程为此提供了非阻塞锁。将 connect() 函数转换为挂起函数后,您可以以线性方式实现您的逻辑,这很简单,不需要任何类型的观察。