Kotlin流Java互操作回调
当我想将Kotlin流与普通回调一起使用时,我一直在寻找合适的解决方案或最佳实践。我的用例是,我编写了一个kotlin库,它在内部使用kotlin流,我必须假设用户将使用Java。因此,我认为最好的解决方案是将一个基本回调接口重载到我的flow方法中,并在Kotlin流Java互操作回调,java,kotlin,kotlin-coroutines,kotlin-flow,Java,Kotlin,Kotlin Coroutines,Kotlin Flow,当我想将Kotlin流与普通回调一起使用时,我一直在寻找合适的解决方案或最佳实践。我的用例是,我编写了一个kotlin库,它在内部使用kotlin流,我必须假设用户将使用Java。因此,我认为最好的解决方案是将一个基本回调接口重载到我的flow方法中,并在collect中调用它,如下所示: class KotlinClass { interface Callback { fun onResult(result: Int) } private fun f
collect
中调用它,如下所示:
class KotlinClass {
interface Callback {
fun onResult(result: Int)
}
private fun foo() = flow {
for (i in 1..3) {
emit(i)
}
}
fun bar(callback: Callback) {
runBlocking {
foo().collect { callback.onResult(it) }
}
}
private fun main() {
bar(object : Callback {
override fun onResult(result: Int) {
TODO("Not yet implemented")
}
})
}
在我的Java应用程序中,我可以这样简单地使用它:
public class JavaClass {
public void main() {
KotlinClass libraryClass = new KotlinClass();
libraryClass.bar(new KotlinClass.Callback() {
@Override
public void onResult(int result) {
// TODO("Not yet implemented")
}
});
}
}
public class JavaClass {
public static void main(String[] args) {
KotlinClass libraryClass = new KotlinClass();
libraryClass.bar(v -> { System.out.println(v); return Unit.INSTANCE; });
}
}
我不确定该怎么办,因为我希望我的Kotlin库能够以一种良好的方式使用Java和Kotlin可用的流
我遇到了
callbackFlow
,但这似乎只是我想让我们把它称为基于回调的API?因为我是Kotlin和Flows的新手,如果我的问题由于缺少Kotlin的一些基本概念而存在缺陷,请道歉。您不需要在Kotlin代码中创建接口。您可以这样定义条形图:
fun bar(callback: (Int) -> Unit) {
runBlocking {
foo().collect { callback(it) }
}
}
从Java代码中,您可以这样调用函数:
public class JavaClass {
public void main() {
KotlinClass libraryClass = new KotlinClass();
libraryClass.bar(new KotlinClass.Callback() {
@Override
public void onResult(int result) {
// TODO("Not yet implemented")
}
});
}
}
public class JavaClass {
public static void main(String[] args) {
KotlinClass libraryClass = new KotlinClass();
libraryClass.bar(v -> { System.out.println(v); return Unit.INSTANCE; });
}
}
您不需要在Kotlin代码中创建接口。您可以这样定义条形图:
fun bar(callback: (Int) -> Unit) {
runBlocking {
foo().collect { callback(it) }
}
}
从Java代码中,您可以这样调用函数:
public class JavaClass {
public void main() {
KotlinClass libraryClass = new KotlinClass();
libraryClass.bar(new KotlinClass.Callback() {
@Override
public void onResult(int result) {
// TODO("Not yet implemented")
}
});
}
}
public class JavaClass {
public static void main(String[] args) {
KotlinClass libraryClass = new KotlinClass();
libraryClass.bar(v -> { System.out.println(v); return Unit.INSTANCE; });
}
}
我会给Java客户机更多的流量控制权。我将向回调接口添加一个
onStart
和onCompletion
方法。除此之外,我还将使用自己的CoroutineScope
——可能可以从Java客户端自定义。我不会在Kotlin函数中阻止调用线程-norunBlocking
@InternalCoroutinesApi
class KotlinClass {
val coroutineScope = CoroutineScope(Dispatchers.Default)
interface FlowCallback {
@JvmDefault
fun onStart() = Unit
@JvmDefault
fun onCompletion(thr: Throwable?) = Unit
fun onResult(result: Int)
}
private fun foo() = flow {
for (i in 1..3) {
emit(i)
}
}
fun bar(flowCallback: FlowCallback) {
coroutineScope.launch {
foo().onStart { flowCallback.onStart() }
.onCompletion { flowCallback.onCompletion(it) }
.collect { flowCallback.onResult(it) }
}
}
fun close() {
coroutineScope.cancel()
}
}
现在,Java客户机完全可以控制如何启动、收集和取消流。例如,您可以使用闩锁等待完成,设置超时并取消例程作用域。这首先看起来像很多代码,但通常需要这种灵活性
public class JavaClass {
public static void main(String[] args) throws InterruptedException {
CountDownLatch latch = new CountDownLatch(1);
KotlinClass libraryClass = new KotlinClass();
libraryClass.bar(new KotlinClass.FlowCallback() {
@Override
public void onCompletion(@Nullable Throwable thr) {
latch.countDown();
}
@Override
public void onResult(int result) {
System.out.println(result);
}
});
try {
latch.await(5, TimeUnit.SECONDS);
} finally {
libraryClass.close();
}
}
}
我会给Java客户机更多的流量控制权。我将向回调接口添加一个
onStart
和onCompletion
方法。除此之外,我还将使用自己的CoroutineScope
——可能可以从Java客户端自定义。我不会在Kotlin函数中阻止调用线程-norunBlocking
@InternalCoroutinesApi
class KotlinClass {
val coroutineScope = CoroutineScope(Dispatchers.Default)
interface FlowCallback {
@JvmDefault
fun onStart() = Unit
@JvmDefault
fun onCompletion(thr: Throwable?) = Unit
fun onResult(result: Int)
}
private fun foo() = flow {
for (i in 1..3) {
emit(i)
}
}
fun bar(flowCallback: FlowCallback) {
coroutineScope.launch {
foo().onStart { flowCallback.onStart() }
.onCompletion { flowCallback.onCompletion(it) }
.collect { flowCallback.onResult(it) }
}
}
fun close() {
coroutineScope.cancel()
}
}
现在,Java客户机完全可以控制如何启动、收集和取消流。例如,您可以使用闩锁等待完成,设置超时并取消例程作用域。这首先看起来像很多代码,但通常需要这种灵活性
public class JavaClass {
public static void main(String[] args) throws InterruptedException {
CountDownLatch latch = new CountDownLatch(1);
KotlinClass libraryClass = new KotlinClass();
libraryClass.bar(new KotlinClass.FlowCallback() {
@Override
public void onCompletion(@Nullable Throwable thr) {
latch.countDown();
}
@Override
public void onResult(int result) {
System.out.println(result);
}
});
try {
latch.await(5, TimeUnit.SECONDS);
} finally {
libraryClass.close();
}
}
}
谢谢你的回答,我不完全理解的是
倒计时闩锁
的部分,我真的需要从我的Java库中关闭coroutineScope吗,还是在我的Kotlin库中完成后就可以终止它?你也可以从Kotlin中关闭coroutineScope
,阻塞调用线程也是如此。但你的问题是,什么是好的API。如果你在你的图书馆里这样做,你是非常固执己见的,客户是如何使用你的。从我的观点来看,最好让客户端决定阻塞线程是否是一个好主意,以及超时的时间长度。问题是,我真的想隐藏kotlin库中的所有线程,java库应该只在主线程上为每个收集到的流结果获取回调感谢您的回答,我不完全理解的是countdownLatch
的部分,我真的需要从我的Java库中关闭coroutineScope吗?还是在我的Kotlin库中完成时终止它?你也可以从Kotlin中关闭coroutineScope
,阻塞调用线程也是如此。但你的问题是,什么是好的API。如果你在你的图书馆里这样做,你是非常固执己见的,客户是如何使用你的。从我的观点来看,让客户端决定阻塞线程是否是一个好主意,以及超时的时间长度是否更好。问题是,我真的想在kotlin库中隐藏所有线程,java库应该只在主线程上为每个收集到的流结果获取回调。这是一个有效的建议,但我想使用returnunit.INSTANCE
在我的java代码中是不好的做法,就像这里描述的:?要在我的java代码中使用Unit
类,我是否需要添加一些kotlin依赖项,因为我不能直接使用它?本文说“目前,还没有办法定义一个参数类型作为Java和Kotlin中的lambda使用,从而让两种语言都觉得它是惯用的。当前的建议是,尽管返回类型为Unit时Java的体验有所降低,但还是更喜欢函数类型。如果您在Java项目中使用kotlin,它应该已经包含kotlin stdlib作为依赖项,不是吗?如果您的库将专门从Java使用,您也可以尝试最后一个建议“定义命名,这是一个有效的建议,但我认为在我的Java代码中使用return Unit.INSTANCE
将是一种糟糕的做法,就像这里所描述的:?要在我的Java代码中使用Unit
类,我是否需要添加一些kotlin依赖项,因为我不能直接使用它?本文说“目前,还没有办法定义一个参数类型作为Java和Kotlin中的lambda使用,从而使它在两种语言中都感觉是惯用的。当前的建议是,尽管返回类型为Unit时Java的体验有所降低,但还是更喜欢函数类型。如果您在Java项目中使用kotlin,它应该已经包含kotlin stdlib作为依赖项,不是吗?如果您的库将专门从Java使用,您也可以尝试最后一个建议“定义命名,Java中的SAM接口”。