【问题标题】:Listen to Kotlin coroutine flow from iOS从 iOS 收听 Kotlin 协程流程
【发布时间】:2021-01-18 08:10:13
【问题描述】:

我已经设置了一个 Kotlin 多平台项目并附加了一个 SQLDelight 数据库。它的所有设置和运行都正确,因为我使用以下方法在 android 端对其进行了测试:

commonMain:

    val backgroundColorFlow: Flow<Color> =
            dbQuery.getColorWithId(BGColor.id)
                    .asFlow()
                    .mapToOneNotNull()

在 Android 项目MainActivity.kt 中使用:

database.backgroundColorFlow.onEach { setBackgroundColor(it.hex) }.launchIn(lifecycleScope)

但是当尝试在 iOS 项目应用程序委托中访问相同的调用时,我得到以下选项,我不确定如何使用它们或将它们转换为我的 BGColor 对象:

database.backgroundColorFlow.collect(collector: T##Kotlinx_coroutines_coreFlowCollector, completionHandler: (KotlinUnit?, Error?) -> Void)

谁能帮我看看这个怎么用?

【问题讨论】:

  • 您找到解决方案了吗?我遇到了同样的问题。
  • 是的,我有!给我几分钟时间回答:)

标签: swift kotlin-coroutines kotlin-multiplatform


【解决方案1】:

所以这通过创建一个流助手来解决:

import io.ktor.utils.io.core.Closeable
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*

fun <T> Flow<T>.asCommonFlow(): CommonFlow<T> = CommonFlow(this)
class CommonFlow<T>(private val origin: Flow<T>) : Flow<T> by origin {
    fun watch(block: (T) -> Unit): Closeable {
        val job = Job()

        onEach {
            block(it)
        }.launchIn(CoroutineScope(Dispatchers.Main + job))

        return object : Closeable {
            override fun close() {
                job.cancel()
            }
        }
    }
}

我的backgroundColorFlow var 更新如下以使用此助手:

    val backgroundColorFlow: CommonFlow<BGColor> =
            dbQuery.getColorWithId(BGColor.id)
                    .asFlow()
                    .mapToOneNotNull()
                    .map { BGColor(it.name) }
                    .asCommonFlow()

然后我的 swift 工作如下:

database.backgroundColorFlow.watch { color in
            guard let colorHex = color?.hex else {
                return
            }
            self.colorBehaviourSubject.onNext(colorHex)
        }

和安卓一样:

database.backgroundColorFlow.watch { setBackgroundColor(it.hex) }

希望这可以帮助遇到此问题的任何人。我想将 CommonFlow 类转换为 Flow 的扩展,但没有专业知识 atm,所以如果有的话,恕我直言,这将是一个更好的解决方案

【讨论】:

    【解决方案2】:

    您可以使用上面提到的收集方法快速完成 FlowCollector 是一个可以用来收集 Flow 对象数据的协议。

    通用示例实现可能如下所示:

    class Collector<T>: FlowCollector {
    
        let callback:(T) -> Void
    
        init(callback: @escaping (T) -> Void) {
            self.callback = callback
        }
    
    
        func emit(value: Any?, completionHandler: @escaping (KotlinUnit?, Error?) -> Void) {
            // do whatever you what with the emitted value
            callback(value as! T)
    
            // after you finished your work you need to call completionHandler to 
            // tell that you consumed the value and the next value can be consumed, 
            // otherwise you will not receive the next value
            //
            // i think first parameter can be always nil or KotlinUnit()
            // second parameter is for an error which occurred while consuming the value
            // passing an error object will throw a NSGenericException in kotlin code, which can be handled or your app will crash
            completionHandler(KotlinUnit(), nil) 
        }
    }
    

    第二部分是调用Flow.collect函数

    database.backgroundColorFlow.collect(collector: Collector<YourValueType> { yourValue in 
        // do what ever you want
    }) { (unit, error) in 
        // code which is executed if the Flow object completed 
    }
    

    可能你也喜欢写一些扩展函数来增加可读性

    【讨论】:

    • 完美,只需将 FlowCollector 替换为 Kotlinx_coroutines_coreFlowCollector
    猜你喜欢
    • 2019-09-30
    • 2021-01-04
    • 2021-04-19
    • 2020-04-12
    • 2021-06-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-19
    相关资源
    最近更新 更多