Les*_*aRB 7 kotlin kotlin-coroutines
我有Kotlin界面
interface FileSystem {
suspend fun getName(path: Path): List<String>
}
Run Code Online (Sandbox Code Playgroud)
我怎么能用Java调用它?什么是
Continuation <? super List<String>>
Run Code Online (Sandbox Code Playgroud)
Kotlin使用常规的基于堆栈的调用约定和连续传递样式(CPS)的组合来实现协程。为此,它通过添加隐式参数对所有对象执行CPS转换suspend fun
,您可以使用该对象从调用函数的位置继续执行程序。这就是Kotlin如何设法在函数体内暂停执行的诀窍:提取延续对象,将其保存在某个地方,然后使函数返回(尚未产生其值)。稍后,它可以通过调用延续对象来实现跳入功能主体中间的效果。
延续基本上是一个回调对象,就像异步Java API中熟悉的那样。可悬挂函数不返回其结果,而是将其结果传递给延续。要从suspend fun
Java 调用,您必须创建这样的回调。这是一个例子:
Continuation<List<String>> myCont = new Continuation<List<String>>() {
@Override public void resume(List<String> result) {
System.out.println("Result of getName is " + result);
}
@Override public void resumeWithException(Throwable throwable) {
throwable.printStackTrace();
}
@NotNull @Override public CoroutineContext getContext() {
return Unconfined.INSTANCE;
}
};
Run Code Online (Sandbox Code Playgroud)
注意:以上仅适用于实验协程。在最终的API中,只有一种恢复方法:结果类型与的区别联合
resumeWith(result: Result<T>)
在哪里,这使得从Java无法访问它。Result
internal class Failure
我们还创建FileSystem
接口的模拟实现:
class MockFs : FileSystem {
override suspend fun getName(path: Path): List<String> {
suspendCoroutine<Unit> {
println("getName suspended")
}
println("getName resumed")
return listOf("usr", "opt")
}
}
Run Code Online (Sandbox Code Playgroud)
现在我们可以从Java调用它了:
Object result = new MockFs().getName(Paths.get(""), myCont);
System.out.println("getName returned " + result);
Run Code Online (Sandbox Code Playgroud)
它打印
getName suspended
getName returned
kotlin.coroutines.experimental.intrinsics.CoroutineSuspendedMarker@6ce253f1
Run Code Online (Sandbox Code Playgroud)
getName()
返回一个特殊的标记对象,该对象指示函数已暂停。一旦恢复,该函数会将其实际结果传递给我们的回调。
现在让我们进行改进,MockFs
以便我们可以访问延续:
class MockFs : FileSystem {
var continuation : Continuation<Unit>? = null
override suspend fun getName(path: Path): List<String> {
suspendCoroutine<Unit> {
continuation = it
println("getName suspended")
}
println("getName resumed")
return listOf("usr", "opt")
}
}
Run Code Online (Sandbox Code Playgroud)
现在,我们将能够手动恢复继续。我们可以使用以下代码:
MockFs mockFs = new MockFs();
mockFs.getName(Paths.get(""), myCont);
mockFs.getContinuation().resume(Unit.INSTANCE);
Run Code Online (Sandbox Code Playgroud)
这将打印
getName suspended
getName resumed
Result of getName is [usr, opt]
Run Code Online (Sandbox Code Playgroud)
在现实生活中,当结果可用时,可挂起的函数将使用某种机制来使自身恢复。例如,如果它是一些异步API调用的包装,它将注册一个回调。当异步API调用回调时,它将依次调用我们的延续。您不需要像我们的模拟代码中那样手动恢复它。
A suspend fun
还可以选择直接返回其结果。例如,使用此MockFs
代码
class MockFs : FileSystem {
override suspend fun getName(path: Path) = listOf("usr", "opt")
}
Run Code Online (Sandbox Code Playgroud)
在Java中,我们可以说
System.out.println(new MockFs().getName(Paths.get(""), myCont));
Run Code Online (Sandbox Code Playgroud)
它将打印[usr, opt]
。我们甚至可以通过的空实现Continuation
。
最苛刻的情况发生在您事先不知道该函数是否将自身挂起的情况下。在这种情况下,一种好的方法是在呼叫站点编写以下内容:
Object retVal = mockFs.getName(Paths.get(""), myCont);
if (retVal != IntrinsicsKt.getCOROUTINE_SUSPENDED()) {
myCont.resume((List<String>) retVal);
}
Run Code Online (Sandbox Code Playgroud)
否则,您将不得不重复处理该函数结果的代码。
归档时间: |
|
查看次数: |
1694 次 |
最近记录: |