【问题标题】:Live data observer inside CoroutineWorkerCoroutineWorker 中的实时数据观察者
【发布时间】:2021-08-01 08:03:27
【问题描述】:

我有一个定期执行的 Worker。它连接到 BLE 设备并从中同步数据。连接由观察者完成。 doWork 调用 syncRides()。 syncRides 创建了一个 observeForever,并开始连接,当连接建立时调用 BleClient.runBleSync()。

我担心的是每 15 分钟(最短 WorkManager 时间)调用一次“observeForever”,并创建未删除的 observeForever。问题是 BleWorker 没有用于创建“BleClient.connectionStatus.observe”而不是“BleClient.connectionStatus.observeForever”的 LifecycleOwner。我的问题是我是否应该担心使用 observeForever 并每 15 分钟触发一次。或者,也许您可​​以建议更好的选择,例如添加和删除观察者。

此外,在没有 GlobalScope.launch(Dispatchers.Main) 的情况下运行时,会出现此函数无法在后台线程上运行的错误。那么在Worker中运行时Dispatchers.Main是什么意思呢?

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)
 }
}

【问题讨论】:

  • IMO LiveData 不能替代 listener 。您的用例显然是 Listener 的实现。我认为您可以更好地为此使用侦听器,因为您已经拥有BleClient 的对象。 LiveData 似乎是这个用例的过度杀伤力,因为它具有生命周期意识,并且在您的案例中没有可用的生命周期所有者。

标签: android kotlin kotlin-coroutines android-workmanager


【解决方案1】:

我假设该应用程序通过蓝牙连接到另一台设备的任何同步数据。如果我的假设是正确的,首先,您应该将同步过程卸载到前台服务,因为该过程需要很长时间。您仍然可以使用 WorkManager 进行调度。在前台服务中,您应该连接 BLE 并同步数据。为此,有不同的选择。如果您需要使用 observable 来观察连接状态,您应该使用 MutableSharedFlow 而不是 MutableLiveData,这样您就可以通过在 Service 类中创建的生命周期范围来观察变化。但是,在我看来,更好的做法是将您的 connect() 函数转换为可暂停函数。为此,您可以使用 suspendCoroutine 构建器进行转换。另外,如果你同时从不同的线程调用连接函数,你必须使用锁来避免多重连接。 Kotlin Coroutines 对此有非阻塞锁。将您的 connect() 函数转换为挂起函数后,您可以以线性方式实现您的逻辑,这很容易并且不需要任何类型的观察。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-05-11
    • 2020-06-25
    • 2014-01-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-15
    相关资源
    最近更新 更多