简体   繁体   中英

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

It is recommended to not use GlobalScope and runBlocking. I have implemented changes in order to this topic: End flow/coroutines task before go further null issue

However it doesn't work well as previously with runBlocking. In brief icon doesn't change, data is not on time. My case is to change icon depending on the boolean.

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

viewmodel

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

fragment

    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
    }

on method onViewCreated I have initToolbar to check if it's true and make action, with runBlokcing worked.

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

coroutine job before change, it worked well

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

Another question is I have the same thing to do in MainActivity, but I do not use there a flow just suspend function.

UseCase

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

MainActivity

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

MainViewmodel

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

You can try to update the icon in the collect block:

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

Using runBlocking you are blocking the Main Thread , which may cause an ANR .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM