如何覆盖 java class 中的挂起函数
How to Override a suspend function in java class
考虑以下 kotlin 接口:
LoginRepository.kt
interface LoginRepository {
suspend fun login(): LoginResponse
}
LoginRepo.java
class LoginRepo implements LoginRepository {
public Object login(@NonNull Continuation<? super LoginResponse> $completion) {
api.login((result) -> {
ContinuationUtilsKt.resumeContinuationWithSuccess($completion, result);
});
return null;
}
}
ContinuationUtils.kt
fun <T> resumeContinuationWithSuccess(cont: Continuation<T>, value: T) {
cont.resumeWith(Result.success(value))
}
我试图将代码深入到它的基本部分,即在 java class 中覆盖的挂起函数进行 API 调用和 return 是使用延续对象的成功或失败延续,return 是 null。
但是,方法 LoginRepository.login
调用时 returns null
.
LoginRepo
中重写的方法签名由 IDE 生成。
我应该 return 一些对象而不是 null
吗?或者我缺少的其他内容。
我真的不认为你应该这样做。在 Kotlin 中用于实现它的功能和 类 是 internal/private 并且从 Java 侧隐藏。
基本上,您需要拦截原始的 Continuation 并使用您的 return 值恢复新的 returned Continuation。然后 return Intrinsics.COROUTINE_SUSPENDED
表示您没有同步 returning 一个值。如果 return 值是 Intrinsics.COROUTINE_SUSPENDED
以外的任何值,那么我认为它假设您直接 returning 挂起函数声明的 return 值。
虽然此代码可能有效,但它可能无法处理所有边缘情况,并且可能不会在发生崩溃时提供有用的堆栈跟踪。标准库实现要复杂得多。
class LoginRepo implements LoginRepository {
public Object login(@NonNull Continuation<? super LoginResponse> $completion) {
Continuation<? super LoginResponse> cont = IntrinsicsKt.intercepted($completion);
api.login((result) -> {
ContinuationUtilsKt.resumeContinuationWithSuccess(cont, result);
});
return IntrinsicsKt.getCOROUTINE_SUSPENDED();
}
}
Kotlin 与 Java 的互操作性并不真正包含挂起函数。暂停函数是 Kotlin 特有的,它们很难从 Java.
调用和实现
在大多数情况下,我建议甚至不要尝试处理来自 Java 的延续和可暂停代码,而是在 Kotlin 中创建小型“适配器”。这些适配器会将可挂起的代码从 Java 翻译成更有用的代码。例如,在 Kotlin 中,可以很容易地在挂起函数和 CompletableFuture
之间进行双向转换。
你的情况比较棘手,因为你需要实现一个接口。尽管如此,Kotlin 还是有办法处理这个问题的。例如,我们可以在 Kotlin 中创建 LoginRepository
的抽象实现。它将提供 login()
,但您将在 Java 中实现所有剩余的方法。我们可以使用组合而不是继承来做类似的事情,方法是在 Kotlin 中创建 LoginRepository
的 non-abstract 实现(从所有不相关的函数中抛出错误)并从 Java [=33] 委托给它=].或者我们可以创建一个静态函数,执行从 callback-based API 到挂起 API 的转换。这个解决方案是最灵活的,但是我们需要弄乱来自 Java:
的一些协程内部结构
@file:JvmName("SuspendUtils")
// utility function in Kotlin, it converts callback API to a suspend function
suspend fun login(api: Api): LoginResponse = suspendCoroutine { cont ->
api.login { cont.resume(it) }
}
public static class LoginRepo implements LoginRepository {
private Api api = new Api();
@Nullable
@Override
public Object login(@NotNull Continuation<? super String> $completion) {
return SuspendUtils.login(api, $completion);
}
}
考虑以下 kotlin 接口:
LoginRepository.kt
interface LoginRepository {
suspend fun login(): LoginResponse
}
LoginRepo.java
class LoginRepo implements LoginRepository {
public Object login(@NonNull Continuation<? super LoginResponse> $completion) {
api.login((result) -> {
ContinuationUtilsKt.resumeContinuationWithSuccess($completion, result);
});
return null;
}
}
ContinuationUtils.kt
fun <T> resumeContinuationWithSuccess(cont: Continuation<T>, value: T) {
cont.resumeWith(Result.success(value))
}
我试图将代码深入到它的基本部分,即在 java class 中覆盖的挂起函数进行 API 调用和 return 是使用延续对象的成功或失败延续,return 是 null。
但是,方法 LoginRepository.login
调用时 returns null
.
LoginRepo
中重写的方法签名由 IDE 生成。
我应该 return 一些对象而不是 null
吗?或者我缺少的其他内容。
我真的不认为你应该这样做。在 Kotlin 中用于实现它的功能和 类 是 internal/private 并且从 Java 侧隐藏。
基本上,您需要拦截原始的 Continuation 并使用您的 return 值恢复新的 returned Continuation。然后 return Intrinsics.COROUTINE_SUSPENDED
表示您没有同步 returning 一个值。如果 return 值是 Intrinsics.COROUTINE_SUSPENDED
以外的任何值,那么我认为它假设您直接 returning 挂起函数声明的 return 值。
虽然此代码可能有效,但它可能无法处理所有边缘情况,并且可能不会在发生崩溃时提供有用的堆栈跟踪。标准库实现要复杂得多。
class LoginRepo implements LoginRepository {
public Object login(@NonNull Continuation<? super LoginResponse> $completion) {
Continuation<? super LoginResponse> cont = IntrinsicsKt.intercepted($completion);
api.login((result) -> {
ContinuationUtilsKt.resumeContinuationWithSuccess(cont, result);
});
return IntrinsicsKt.getCOROUTINE_SUSPENDED();
}
}
Kotlin 与 Java 的互操作性并不真正包含挂起函数。暂停函数是 Kotlin 特有的,它们很难从 Java.
调用和实现在大多数情况下,我建议甚至不要尝试处理来自 Java 的延续和可暂停代码,而是在 Kotlin 中创建小型“适配器”。这些适配器会将可挂起的代码从 Java 翻译成更有用的代码。例如,在 Kotlin 中,可以很容易地在挂起函数和 CompletableFuture
之间进行双向转换。
你的情况比较棘手,因为你需要实现一个接口。尽管如此,Kotlin 还是有办法处理这个问题的。例如,我们可以在 Kotlin 中创建 LoginRepository
的抽象实现。它将提供 login()
,但您将在 Java 中实现所有剩余的方法。我们可以使用组合而不是继承来做类似的事情,方法是在 Kotlin 中创建 LoginRepository
的 non-abstract 实现(从所有不相关的函数中抛出错误)并从 Java [=33] 委托给它=].或者我们可以创建一个静态函数,执行从 callback-based API 到挂起 API 的转换。这个解决方案是最灵活的,但是我们需要弄乱来自 Java:
@file:JvmName("SuspendUtils")
// utility function in Kotlin, it converts callback API to a suspend function
suspend fun login(api: Api): LoginResponse = suspendCoroutine { cont ->
api.login { cont.resume(it) }
}
public static class LoginRepo implements LoginRepository {
private Api api = new Api();
@Nullable
@Override
public Object login(@NotNull Continuation<? super String> $completion) {
return SuspendUtils.login(api, $completion);
}
}