fragments 和 activity 中 runBlocking Coroutines 的替代品是什么?

What is the substitute for runBlocking Coroutines in fragments and activities?

建议不要使用GlobalScope和runBlocking。 为了这个主题,我已经实施了更改:

但是,使用 runBlocking 时效果不如以前。总之图标没有变化,数据不及时。 我的情况是根据布尔值更改图标。

流用例


class GetNotificationListItemDetailsUseCase @Inject constructor(private val notificationDao: NotificationDao): BaseFlowUseCase<Unit, List<NotificationItemsResponse.NotificationItemData>>() {
    override fun create(params: Unit): Flow<List<NotificationItemsResponse.NotificationItemData>> {
        return flow{
            emit(notificationDao.readAllData())
        }
    }
}

视图模型

    val actualNotificationList: Flow<List<NotificationItemsResponse.NotificationItemData>> = getNotificationListItemDetailsUseCase.build(Unit)
    

片段

    private fun getActualNotificationList() : Boolean {
        lifecycleScope.launch {
            vm.actualNotificationList
                .flowWithLifecycle(lifecycle, Lifecycle.State.STARTED)
                .collect { response ->
                    notificationData.value = response
                    val notificationDataString = notificationData.value.toString()
                    val stringToCheck = "isRead=false"
                    isNotificationNotRead = (notificationDataString.contains(stringToCheck))
                }
        }
        return isNotificationNotRead
    }

在 onViewCreated 方法上,我有 initToolbar 来检查它是否正确并采取行动,runBlokcing 有效。

fun initToolbar{
        if (onReceived) {
            Log.d("onReceivedGoes", "GOES IF")
        } else {
            Log.d("onReceivedGoes", "GOES ELSE")
            getActualNotificationList()
        }
        onReceived = false

        val item = menu.findItem(R.id.action_notification_list)
        when {
            isNotificationNotRead && !isOutcomed -> {
                item.setIcon(R.drawable.image_icon_change)
            }
}

更改前的协程作业,效果很好

        val job = GlobalScope.launch {
            vm.getNotificationListItemDetailsUseCase.build(Unit).collect {
                notificationData.value = it
                val notificationDataString = notificationData.value.toString()
                val stringToCheck = "isRead=false"
                isNotificationNotRead = (notificationDataString.contains(stringToCheck))
            }
        }
        runBlocking {
            job.join()
        }
    }

另一个问题是我在 MainActivity 中有同样的事情要做,但我不在那里使用流只是挂起功能。

用例

class UpdateNotificationListItemUseCase @Inject constructor(private val notificationDao: NotificationDao): BaseUpdateBooleanUseCase<Int, Boolean, Boolean, Boolean, Unit>() {
    override suspend fun create(itemId: Int, isRead: Boolean, isArchived: Boolean, isAccepted: Boolean){
        notificationDao.updateBooleans(itemId, isRead, isArchived, isAccepted)
    }
}

主要活动

            val job = GlobalScope.launch { vm.getIdWithUpdate() }
            runBlocking {
                job.join()
            }

主视图模型

suspend fun getIdWithUpdate() {
        var id = ""
        id = notificationAppSessionStorage.getString(
            notificationAppSessionStorage.getIncomingKeyValueStorage(),
            ""
        )
        if (id != "") {
           
            updateNotificationListItemUseCase.build(id.toInt(), true, false, false)
        }
    }
}

编辑 1:

分片收集效果很好,谢谢

MainActivity 和使用这个用例如何在没有流程的情况下暂停乐趣。

我已阅读文档https://developer.android.com/kotlin/coroutines/coroutines-best-practices

        val IODispatcher: CoroutineDispatcher = Dispatchers.IO
        val externalScope: CoroutineScope = CoroutineScope(IODispatcher)
            suspend {
                externalScope.launch(IODispatcher) {
                    vm.getIdWithUpdate()
                }.join()
            }

第二个选项,但这里我不等到工作完成

            suspend {
                withContext(Dispatchers.IO) {
                    vm.getIdWithUpdate()
                }
            }

你怎么看?

您可以尝试更新collect块中的图标:

private fun getActualNotificationList() = lifecycleScope.launch {
        vm.actualNotificationList
            .flowWithLifecycle(lifecycle, Lifecycle.State.STARTED)
            .collect { response ->
                notificationData.value = response
                val notificationDataString = notificationData.value.toString()
                val stringToCheck = "isRead=false"
                val isNotificationNotRead = (notificationDataString.contains(stringToCheck))

                val item = menu.findItem(R.id.action_notification_list)
                when {
                    isNotificationNotRead && !isOutcomed -> {
                        item.setIcon(R.drawable.image_icon_change)
                    }
                }
            }
}

使用 runBlocking 您正在阻塞 主线程 ,这可能会导致 ANR.