Android Kotlin 连续运行两个协程

问题描述 投票:0回答:1

我正在尝试连续运行两个协程启动。我怎样才能存档这个?

第一个尝试获取持续时间。当成功时,收集应该停止,并且我的协程中的第二次启动应该运行。

我不知道这是否是正确的方法。但我需要先获取 Duration,然后处理第二部分。

仅此部分即可工作。但不能一起,因为收集是阻塞的。我也尝试过 return@collect,但不起作用

@Singleton
class AddDayReminderNotification(
    private val notificationUseCases: NotificationUseCases,
    private val dayUseCases: DayUseCases,
    private val weekUseCases: WeekUseCases,
    private val settingsUseCases: SettingsUseCases
) {
    suspend fun addNotification(context: Context?, notification: Notification) {

        var neededDuration: Duration = Duration.ZERO
        val dayOfWeekIndex = getDayOfWeekLocalized(notification.date)

        coroutineScope {

            val dayDuration = launch {
                weekUseCases.getAllWeeks()
                    .collect { weekResponse ->
                        when (weekResponse) {
                            is Response.Failure -> {
                                coroutineContext.cancel()
                            }

                            is Response.Loading -> {}
                            is Response.Success -> {
                                val week =
                                    weekResponse.data?.firstOrNull {
                                        it.week == getWeekOfYearByLocalDate(
                                            notification.date
                                        ) && it.year == notification.date.year
                                    }
                                if (week != null) {
                                    val stringValue = week.weekDailyDurations

                                    val splitString = stringValue.split(":")

                                    val intList: MutableList<Int> = mutableListOf()
                                    if (splitString.count() == 7) {

                                        splitString.forEach {
                                            try {
                                                intList.add(it.toInt())
                                            } catch (e: NumberFormatException) {
                                                println("Error: $it is not a valid integer")
                                                coroutineContext.cancel()
                                            }
                                        }
                                    }
                                    neededDuration = intList[dayOfWeekIndex].minutes
                                } else {
                                    settingsUseCases.getSetting(SettingsIndex.WeekDailyDurations.getIndex())
                                        .collect { response ->
                                            when (response) {
                                                is Response.Failure -> {
                                                    coroutineContext.cancel()
                                                }

                                                is Response.Loading -> {}
                                                is Response.Success -> {
                                                    val stringValue = response.data?.stringValue

                                                    if (stringValue.isNullOrEmpty()) {
                                                        coroutineContext.cancel()
                                                    } else {

                                                        val splitString = stringValue.split(":")
                                                        val intList: MutableList<Int> =
                                                            mutableListOf()
                                                        if (splitString.count() == 7) {

                                                            splitString.forEach {
                                                                try {
                                                                    intList.add(it.toInt())
                                                                } catch (e: NumberFormatException) {
                                                                    println("Error: $it is not a valid integer")
                                                                    coroutineContext.cancel()
                                                                }
                                                            }
                                                        }
                                                        neededDuration = intList[dayOfWeekIndex].minutes
                                                    }
                                                }
                                            }
                                        }
                                }
                            }
                        }
                    }
            }

            val notificationCreator = launch {
                if (neededDuration != Duration.ZERO) {
                    dayUseCases.getAllDays()
                        .collect { dayResponse ->
                            when (dayResponse) {
                                is Response.Failure -> {
                                    coroutineContext.cancel()
                                }

                                is Response.Loading -> {}
                                is Response.Success -> {
                                    if (dayResponse.data != null) {
                                        val foundDay =
                                            dayResponse.data.firstOrNull { it.date == notification.date && it.isActive }
                                        if (foundDay == null) {
                                            notificationUseCases.getAllNotifications()
                                                .collect { notificationResponse ->
                                                    when (notificationResponse) {
                                                        is Response.Failure -> {
                                                            coroutineContext.cancel()
                                                        }

                                                        is Response.Loading -> {}
                                                        is Response.Success -> {
                                                            if (notificationResponse.data != null) {
                                                                val dayReminderNotification =
                                                                    notificationResponse.data.firstOrNull { it.date == notification.date && it.notificationType == NotificationType.DayUnchangedReminder.value }
                                                                if (dayReminderNotification == null) {
                                                                    notificationUseCases.upsertNotification(
                                                                        notification
                                                                    )
                                                                    context?.let {
                                                                        DayReminderNotificationService(
                                                                            it
                                                                        )
                                                                    }
                                                                        ?.showNotification(
                                                                            notification.title + neededDuration.toFloatHours(),
                                                                            notification.description,
                                                                            notification.notificationType
                                                                        )
                                                                }
                                                                coroutineContext.cancel()
                                                            }
                                                        }
                                                    }
                                                }
                                        }
                                        coroutineContext.cancel()
                                    }
                                }
                            }
                        }
                } else {
                    coroutineContext.cancel()
                }
            }
        }
    }
}
android kotlin coroutine collect
1个回答
0
投票

要解决这个问题,关键是要正确管理协程的流程。具体来说,您希望仅在第一个协程成功完成后才启动第二个协程。由于collect是一个挂起函数,它会阻塞当前协程直到完成。因此,依次启动两个协程将无法按预期工作,因为第二个协程可能会在第一个协程完成之前启动。

为了实现您正在寻找的目标,您可以在第一部分使用 async (获取持续时间)并使用 wait() 等待结果,然后再继续第二个协程。

val dayDurationDeferred = async {
    weekUseCases.getAllWeeks()
        .collect { weekResponse ->
            // Your existing code for getting neededDuration
        }
}

// Wait for the first coroutine to complete before proceeding
dayDurationDeferred.await()

// Then proceed with the second part
val notificationCreator = launch {
    if (neededDuration != Duration.ZERO) {
        dayUseCases.getAllDays()
            .collect { dayResponse ->
                // Your existing code for processing notifications
            }
    } else {
        coroutineContext.cancel()
    }
}

需要改变:

对第一个协程使用异步:

异步构建器允许您启动协程并获取可等待稍后获取结果的延迟对象。 收集块将异步执行,但您可以通过在结果上等待()来控制流程,然后再继续第二个协程。

等待结果:

dayDurationDeferred.await() 确保第一部分(获取持续时间)完成,然后再继续处理通知的第二个协程。

请告诉我这是否对您有帮助。

© www.soinside.com 2019 - 2024. All rights reserved.