73

Taking the direct example from https://kotlinlang.org/docs/reference/coroutines/flow.html#flows-are-cold

fun simple(): Flow<Int> = flow { 
    println("Flow started")
    for (i in 1..3) {
        delay(100)
        emit(i)
    }
}

fun main() = runBlocking<Unit> {
    println("Calling simple function...")
    val flow = simple()
    println("Calling collect...")
    flow.collect { value -> println(value) } 
    println("Calling collect again...")
    flow.collect { value -> println(value) } 
}

I got the error on collect.

This is an internal kotlinx.coroutines API that should not be used from outside of kotlinx.coroutines. No compatibility guarantees are provided.It is recommended to report your use-case of internal API to kotlinx.coroutines issue tracker, so stable API could be provided instead

When I add @InternalCoroutinesApi

@InternalCoroutinesApi
fun main() = runBlocking<Unit> {
    println("Calling simple function...")
    val flow = simple()
    println("Calling collect...")
    flow.collect { value -> println(value) }
    println("Calling collect again...")
    flow.collect { value -> println(value) }
}

I get an error in the collect's lambda (function of value -> println(value) as below

Type mismatch.
Required:
FlowCollector<Int>
Found:
([ERROR :  ]) → Unit
Cannot infer a type for this parameter. Please specify it explicitly.

I am using Kotlin version 1.4.21.

    implementation "org.jetbrains.kotlin:kotlin-stdlib:1.4.2"
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.2'
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.1'
    testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.4.2'

Did I do anything wrong that I cannot compile the example code in Android Studio?

Elye
  • 53,639
  • 54
  • 212
  • 474
  • 46
    add `import kotlinx.coroutines.flow.collect` – IR42 Jan 04 '21 at 07:49
  • 1
    @quetzalcoatl, the title is making sense, as apparently Kotlin `collect` is not internal kotlinx.collection.API only. It's the error message that mislead one into thinking it is and go down the wrong solution. – Elye Jan 04 '21 at 09:08
  • hmm.. interesting. Thanks for clarifying. I wonder why this "This is an internal kotlinx.coroutines API that should not be used from outside of kotlinx.coroutines." was generated then. Was there another 'collect' function that was already available (but not fit), or was this error coming from a totally different thing? – quetzalcoatl Jan 04 '21 at 20:29

7 Answers7

111

The answer is, NO, collect is not only internal kotlinx.coroutines API. The error message is misleading.

As per @ir42's comment, add import kotlinx.coroutines.flow.collect solve the problem.

Additional info, why I didn't pick collectLatest as the answer

collect and collectLatest is different.

Using this example

fun simple(): Flow<Int> = flow { // flow builder
    for (i in 1..3) {
        delay(100) // pretend we are doing something useful here
        emit(i) // emit next value
    }
}

fun main() = runBlocking<Unit> {
    // Launch a concurrent coroutine to check if the main thread is blocked
    launch {
        for (k in 1..3) {
            println("I'm not blocked $k")
            delay(100)
        }
    }
    // Collect the flow
    simple().collect { value -> println(value) } 
}

Collect will produce

I'm not blocked 1
1
I'm not blocked 2
2
I'm not blocked 3
3

as per https://kotlinlang.org/docs/reference/coroutines/flow.html

But collectLatest

fun simple(): Flow<Int> = flow { // flow builder
    for (i in 1..3) {
        delay(100) // pretend we are doing something useful here
        emit(i) // emit next value
    }
}

fun main() = runBlocking<Unit> {
    // Launch a concurrent coroutine to check if the main thread is blocked
    launch {
        for (k in 1..3) {
            println("I'm not blocked $k")
            delay(100)
        }
    }
    // Collect the flow
    simple().collectLatest { value -> println(value) } 
}

will produce

I'm not blocked 1
I'm not blocked 2
1
I'm not blocked 3
2
Elye
  • 53,639
  • 54
  • 212
  • 474
  • 7
    import is not working on kotlinx-coroutines-android:1.6.0-RC2 – di0n0s Dec 13 '21 at 21:13
  • 1
    @di0n0s This seems to be an issue specific to 1.6.0-RC2. See this issue report: https://github.com/Kotlin/kotlinx.coroutines/issues/3078 It has been fixed https://github.com/Kotlin/kotlinx.coroutines/pull/3082 so I think it will arrive on the next release. -> Use `1.6.0-RC`, skip `1.6.0-RC2` and wait for the next release. – Peter F Dec 16 '21 at 15:51
  • 1
    @di0n0s version `1.6.0-RC3` has been released and the issue existing in `1.6.0-RC3` has been resolved. It is mentioned in the release notes: https://github.com/Kotlin/kotlinx.coroutines/releases/tag/1.6.0-RC3 – Peter F Dec 17 '21 at 18:33
  • This is still an issue if you use `Flow.flowWithLifecycle.collect()`. I had to switch to using `repeatOnLifecycle` instead. – Gavin Wright Feb 15 '22 at 17:12
  • 1
    how come this misleading error message shows up? @@ – Nguyen Tan Dat Feb 18 '22 at 06:09
20

Add below import:

import kotlinx.coroutines.flow.collect
Rissmon Suresh
  • 13,173
  • 5
  • 29
  • 38
  • 2
    IDEA constantly removing this import as not used/ optimized. without it, I have this compilation error – Victor Mikhailov May 11 '22 at 09:45
  • @VictorMikhailov try to disable import optimization : `File | Settings | Editor | General | Auto Import | Optimize imports on the fly` – Javlon Jan 07 '23 at 07:49
7

I finally found the solution for it after it almost drove me mad. As none of the solutions here worked for me, I had a special case where I was working on a multi-modules project and collect() kept throwing out this error everywhere and even manually importing it didn't fix it.

What solved the issue for me is explicitly adding coroutines dependency to ALL of my project's modules build.gradle files, not just the app's one, even those modules that don't use coroutines.

implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.2")
M.Ed
  • 969
  • 10
  • 12
6

For version 1.6.0-RC3 and newer:

The @InternalCoroutinesApi annotations have been removed from all collect() functions (see this PR).

That means we won't see the error anymore and also won't need the import

import kotlinx.coroutines.flow.collect

anymore because (together with the changes of another PR) we can now use the collect() member function directly.

Peter F
  • 3,633
  • 3
  • 33
  • 45
4

The Api changed in newer versions of kotlinx coroutines and instead of a lambda in the collect function, it should go as the final call in the chain. The documentation example:

flow
  .onEach { value -> process(value) }
  .catch { e -> handleException(e) }
  .collect() // trigger collection of the flow
Rafa
  • 383
  • 3
  • 7
  • According to the above mentioned doc https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/collect.html the collect {} syntax should still work, it says "It is a shorthand for collect {}." .. which it doesn't. The current answer, anyway, should be the accepted answer at the current date. – Madis Männi Aug 02 '23 at 12:56
1

Just casting as the same object (here, StateFlow) worked for me, like below:

(flow as StateFlow).collect { value -> println(value) }
Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
GP K
  • 11
  • 4
-6

Replace collect with collectLatest.

EpicPandaForce
  • 79,669
  • 27
  • 256
  • 428