我将如何“包装”,“懒惰”,在地道的科特林结果缓存函数调用这个并不quite-?(How would

2019-09-30 21:32发布

我不能使用“的懒惰 ”,因为回调需要suspendCoroutine ,这borks在android系统,如果它会阻止主线程,所以我不得不反复使用下面的“缓存结果”的格局。 有没有办法把它包起来的funButUseCachedResultsIfTheyAlreadyExist模式来封装xCached对象?

private var cameraDeviceCached: CameraDevice? = null

private suspend fun cameraDevice(): CameraDevice {
    cameraDeviceCached?.also { return it }
    return suspendCoroutine { cont: Continuation<CameraDevice> ->
        ... deep callbacks with cont.resume(camera) ...
    }.also {
        cameraDeviceCached = it
    }
}

当我真的很想写的是

private suspend fun cameraDevice(): CameraDevice = theMagicFunction { cont ->
    ... deep callbacks with cont.resume(camera) ...
}

Answer 1:

您可以通过包装建立一个广义解async如下电话:

import kotlinx.coroutines.*
import kotlinx.coroutines.CoroutineStart.LAZY

class LazySuspendFun<out T>(
        scope: CoroutineScope,
        private val block: suspend () -> T
) {
    private val deferred = scope.async(Dispatchers.Unconfined, LAZY) { block() }

    suspend operator fun invoke() = deferred.await()
}

fun <T> CoroutineScope.lazySuspendFun(block: suspend () -> T) = 
        LazySuspendFun(this, block)

这是你如何使用它一个简单的例子。 需要注意的是,我们能够让我们使用一个懒惰inited值作为依赖于获得一个又一个撰写他们:

val fetchToken = lazySuspendFun<String> {
    suspendCoroutine { continuation ->
        Thread {
            info { "Fetching token" }
            sleep(3000)
            info { "Got token" }
            continuation.resume("hodda_")
        }.start()
    }
}

val fetchPosts = lazySuspendFun<List<String>> {
    val token = fetchToken()
    suspendCoroutine { continuation ->
        Thread {
            info { "Fetching posts" }
            sleep(3000)
            info { "Got posts" }
            continuation.resume(listOf("${token}post1", "${token}post2"))
        }
    }
}

在通话方面,你必须有一些协同程序上下文中,所以你可以调用暂停功能:

myScope.launch {
   val posts = fetchPosts()
   ...
}

该解决方案是足够强大,你可以同时请求值几次初始化将只运行一次。



Answer 2:

我会写这样一个答案,因为它不可能在评论张贴多的代码。

你正在寻找的是这样的:

private suspend fun cameraDevice() = theMagicFunction {
    CameraDevice()
}()

suspend fun theMagicFunction(block: ()->CameraDevice): () -> CameraDevice {
    var cameraDeviceCached: CameraDevice? = null

    return fun(): CameraDevice {
        cameraDeviceCached?.also { return it }
        return suspendCoroutine { cont: Continuation<CameraDevice> ->
            cont.resume(block())
        }.also {
            cameraDeviceCached = it
        }
    }
}

不幸的是,这不会编译,因为封锁不能悬浮,也不是本地功能。

最好的我可以建议,除非我错过的解决方案有,是在一个类来封装这一点,如果这个变量打扰你太多。



文章来源: How would I “wrap” this not-quite-“by lazy” result caching function call in idiomatic Kotlin?