【问题标题】:What is the substitute for runBlocking Coroutines in fragments and activities?片段和活动中 runBlocking Coroutines 的替代品是什么?
【发布时间】:2022-01-11 14:01:55
【问题描述】:

建议不要使用 GlobalScope 和 runBlocking。 为了这个主题,我已经实施了更改: End flow/coroutines task before go further null issue

但是,它不像以前的 runBlocking 那样工作得很好。简而言之,图标不变,数据不准时。 我的情况是根据布尔值更改图标。

Flow 用例


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

你怎么看?

【问题讨论】:

    标签: android kotlin kotlin-coroutines coroutine kotlin-flow


    【解决方案1】:

    您可以尝试更新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

    【讨论】:

    • 谢谢,它有效。现在我更好地理解了这个收集{}。想在 MainActivity 案例中为我提供建议,并在没有流程的情况下暂停乐趣。我已经阅读了文档并提出了我的建议 -> 我已经编辑了帖子。提前致谢。
    • MainActivity 有什么问题?能否请您在 StackOverflow 上创建另一个问题并详细描述,以便其他人看到,谢谢。
    • 这与我使用带有 runBlocking 的 GlobalScope 相同,但是过段时间我会说的,谢谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-08-29
    • 2016-06-14
    • 2019-02-22
    • 2011-05-07
    • 2012-04-24
    • 2019-12-03
    • 2010-09-17
    相关资源
    最近更新 更多