Почему вызов функции приостановки в лямбде внутри CoroutineScope вызывает ошибку? - PullRequest
2 голосов
/ 28 мая 2020

У меня есть политика повтора, которая принимает лямбду, запускает CoroutineScope, увеличивает счетчик повторов, проверяет, достигнуто ли максимальное количество повторов, вычисляет waitTime на основе количества повторов, задерживает область на это время и, наконец, вызывает лямбда:

        fun connectionRetryPolicy(block: () -> Unit) {

            Timber.d("connectionRetryPolicy: called")

            // Launch the coroutine to wait for a specific delay
            val scope = CoroutineScope(Job() + Dispatchers.Main)
            scope.launch {

                // Get and increment the current retry counter
                val counter = retryCounter.getAndIncrement()

                // Check if the counter is smaller than the maximum retry count and if so, wait a bit and execute the given function
                if (counter < maxRetry) {

                    // Calculate the time to be waited
                    val waitTime: Long = (2f.pow(counter) * baseDelayMillis).toLong()

                    // Delay the scope for the calculated time
                    delay(waitTime)

                    // Execute the given function
                    block()

                }

                // Else, throw an exception
                else {

                    throw FirebaseNetworkException("Retry count reached")

                }

            }

        }

Этот метод вызывается для рекурсивного вызова функции приостановки как лямбда, например:

    private suspend fun connectToGooglePlayBillingService(): BillingResult? {

        Timber.d("connectToGooglePlayBillingService: called")

        return suspendCoroutine { continuation ->

            // If the billingClient is not already ready, start the connection
            if (!playStoreBillingClient.isReady) {

                // Start the connection and wait for its result in the listener
                playStoreBillingClient.startConnection(object: BillingClientStateListener {

                    override fun onBillingServiceDisconnected() {

                        Timber.d("onBillingServiceDisconnected: called")

                        // Retry to connect using the RetryPolicies
                        RetryPolicies.connectionRetryPolicy { connectToGooglePlayBillingService() }

                    }

                    override fun onBillingSetupFinished(billingResult: BillingResult?) {

                        // There is code that does not matter here

                    }

                })

            }

        }

    }

Теперь Линт сообщает мне, что connectToGooglePlayBillingService не может быть вызван внутри лямбда, потому что это функция приостановки, и ее нужно вызывать внутри CoroutineScope. И, как вы можете видеть, я вызываю лямбду внутри CoroutineScope в connectionRetryPolicy.

Это ошибка в Lint или я здесь что-то делаю не так? Я знаю, я могу создать новый CoroutineScope внутри лямбды, а затем вызвать connectToGooglePlayBillingService, и я не уверен, так ли это разумно в отношении производительности.

1 Ответ

2 голосов
/ 28 мая 2020

Замените

fun connectionRetryPolicy(block: () -> Unit)

на

fun connectionRetryPolicy(block: suspend () -> Unit)

, потому что ваш block() будет работать внутри сопрограммы, но другой метод этого не знает.

...