java - 如何从 Java 调用协程(暂停函数和流)?
问题描述
我决定写这个问题,因为还没有关于这个主题的最佳实践。
我们正在提供一个 Android SDK,它使用 Coroutines 实现异步调用。我希望我们的客户使用Flow
Java 或标准 Kotlin 的挂起函数。
我知道有kotlinx-coroutines-jdk8但这只能从 Android Api 级别 24 使用,我们的 SDK 支持 Android 到 Api 级别 21。所以目前这不是一个选项。
我的想法是通过提供一个简单的回调 API 来连接 Java(或标准 Kotlin)和 Coroutines 的世界。
我想知道我的以下方法是否是一个好的解决方案。有什么缺点或危险吗?我必须让客户调用 Coroutines 函数而不强迫他们自己使用 Coroutines 有什么选择?
现在让我们开始吧。首先,我向您展示了一些接口和辅助函数,稍后我可以使用这些接口和辅助函数来映射挂起函数和 Flow。
消除
我需要确保可以从 Java 中取消 Coroutine。所以我创建了一个Cancelable
界面。
interface Cancelable {
fun cancel()
}
该接口由CancelableJob
包含并隐藏Job
要取消的对象实现。
class CancelableJob(private val job: Job) : Cancelable {
override fun cancel() {
job.cancel()
}
}
启动一个新的协程
每次客户调用一个函数时,我都会启动一个新的协程。为此,我创建了一个顶级函数launchCancelableJob
。此函数获取一个暂停块并返回一个Cancelable
. Coroutine 将在 上启动Dispatchers.Main
,因此所有结果都可以在 UI Thread 上观察到,以及SupervisedJob
.
fun launchCancelableJob(block: suspend () -> Unit): Cancelable {
val job: Job = CoroutineScope(Dispatchers.Main + SupervisorJob()).launch {
block.invoke()
}
return CancelableJob(job)
}
将挂起函数和流程桥接到 Java 世界
现在是时候提供一个桥接函数了,它本身不是挂起函数,而是启动协程并返回一个Cancelable
. 从给定的回调中,结果将被传递给调用者。
// normal coroutine api
suspend fun generateQrCode(): QrCode
// bridge function - to be called from Java
fun generateQrCode(callback: (QrCode) -> Unit): Cancelable {
return launchCancelableJob {
val qrCode: QrCode = generateQrCode()
callback(qrcode)
}
}
我可以对 Flow 做同样的事情。
// normal coroutine api
fun generateQrCodes(): Flow<QrCode>
// bridge function - to be called from Java
fun generateQrCodes(callback: (QrCode) -> Unit): Cancelable {
return launchCancelableJob {
generateQrCodes().collect { qrCode: QrCode ->
callback(qrcode)
}
}
}
用法
上面的函数可以从 Java 中调用,例如:
Cancelable cancelable = generateQrCode(new Function1<QrCode, Unit>() {
@Override
public Unit invoke(QrCode qrCode) {
// show the qrCode
return Unit.INSTANCE;
}
});
如果不再需要它可以被取消,如:
cancelable.cancel();
这是我的方法。我真的很期待您的意见或更好的解决方案。感谢您的阅读,我知道这是一个很长的问题。
解决方案
推荐阅读
- java - 无法将类型 [java.lang.String] 的值转换为所需类型 [org.javatuples.Pair]:找不到匹配的编辑器或转换策略
- php - 如何使用在 Nginx 上运行的普通网站中的敏感数据执行 PHP 脚本?
- javascript - 无法在 DOMWindow 上执行 postMessage:目标原点
- firefox - 如何设置 Firefox 不与网站共享信息(浏览器版本、屏幕分辨率、操作系统等)?
- java - 当CSV文件在google bucket中并且mysql 5.7.17安装在云端的RHEL机器上时,如何使用mysql的load data infile?
- ios - Swift 的 Combine 框架 CombineLatest 的问题
- javascript - 正则表达式允许在数字开头或数字之间出现零和一个小数点
- php - 自定义 Child 中的 parents functions.php 文件
- python - MayaVi contour3d after coordinate transformation
- javascript - 子组件更新时如何防止容器组件重新渲染