Kotlin Flow: Suspension functions can be called only within coroutine body

Flowのemitでエラー

例えば、Zipにアーカイブしている最中にprogressをemitできない問題。

fun startPacking() = flow {

    ...

    ZipUtil.pack(baseDir, exportPath) { name ->

        ...

        val progress: Float = packingFiles / totalFiles
        emit(progress)// Suspension functions can be called only within coroutine body
        name
    }

}.flowOn(Dispatchers.IO)

CallbackFlow

こうゆう場合はcallbackFlowに替えると解決します。emit => trySend or send、最後にawaitClose()を呼びます。チェンジリスナーを使っていた場合は、awaitCloseで解放させて下さい。

実験的なので仕様が変わるかもしれません。

@OptIn(ExperimentalCoroutinesApi::class)
fun startPacking() = callbackFlow {

    ...

    ZipUtil.pack(baseDir, exportPath) { name ->

        ...

        val progress: Float = packingFiles / totalFiles
        trySend(progress)
        name
    }
    awaitClose()

}.flowOn(Dispatchers.IO)