【发布时间】:2021-01-18 16:08:10
【问题描述】:
我有一个 c++ 函数,我想从我的 Kotlin 代码中调用它。 那个 c++ 函数获取一个回调函数作为参数,做一些工作并在完成时调用回调。
我之前已经做过几次了,一切都很好。但是,我想以某种方式包装它,而不是传递回调,而是返回一个 Observable,该 Observable 将在调用回调时发出一个值。
我用更简单的代码创建了一个示例。 到目前为止我做了什么:
Kotlin 代码:
fun someFunc(str: String): Observable<String> {
val subject = PublishSubject.create<String>()
nativeFunc(object: TestCallback {
override fun invoke(event: String) {
println("Callback invoked. subject = $subject")
subject.onNext("$event - $str")
}
})
return subject
}
private external fun nativeFunc(callback: TestCallback)
Kotlin 中回调函数的接口:
interface TestCallback {
fun invoke(event: String)
}
本机 JNI 代码:
extern "C"
JNIEXPORT void JNICALL
Java_com_myProject_TestClass_nativeFunc(JNIEnv *env, jobject thiz, jobject callback) {
env->GetJavaVM(&g_vm);
auto g_callback = env->NewGlobalRef(callback);
std::function<void()> * pCompletion = new std::function<void()>([g_callback]() {
JNIEnv *newEnv = GetJniEnv();
jclass callbackClazz = newEnv->FindClass("com/myproject/TestCallback");
jmethodID invokeMethod = newEnv->GetMethodID(callbackClazz, "invoke", "(Ljava/lang/String;)V");
string callbackStr = "Callback called";
newEnv->CallVoidMethod(g_callback, invokeMethod, newEnv->NewStringUTF(callbackStr.c_str()));
newEnv->DeleteGlobalRef(g_callback);
});
pCompletion->operator()(); // <--Similar function is passed to the c++ function. Lets skip that
}
一起运行的测试函数
@Test
fun testSubject() {
val testClass = TestClass()
val someList = listOf("a", "b", "c")
var done = false
Observable.concat(someList.map { testClass.someFunc(it) })
.take(3)
.doOnNext { println("got next: $it") }
.doOnComplete { done = true }
.subscribe()
while (!done);
}
测试函数运行 3 次 someFunc 函数(返回一个 Observable 实例,完成时发出一个字符串)并将所有 Observable 连接在一起。
我希望打印的内容:
Callback invoked. subject = io.reactivex.subjects.PublishSubject@1f7acc8
got next: Callback called - a
Callback invoked. subject = io.reactivex.subjects.PublishSubject@7c9b161
got next: Callback called - b
Callback invoked. subject = io.reactivex.subjects.PublishSubject@6f24486
got next: Callback called - c
然而实际结果是:
Callback invoked. subject = io.reactivex.subjects.PublishSubject@1f7acc8
Callback invoked. subject = io.reactivex.subjects.PublishSubject@7c9b161
Callback invoked. subject = io.reactivex.subjects.PublishSubject@6f24486
似乎一切都按预期工作,但是,尽管这条线
println("Callback invoked. subject = $subject")
打印(带有正确的主题地址), onNext 不工作并且由于某种原因没有发出任何东西。
我检查了没有本机回调的相同功能,一切正常。
有什么建议吗???
【问题讨论】:
-
建议:摆脱 Kotlin 并使用 Java。
-
这对解决问题有什么帮助?
-
您是否有可能阻止执行该打印?如果删除
while循环会发生什么? -
@Michael 测试将结束。没有本机代码的类似功能按预期工作。此外,正在调用回调并打印日志,但我没有看到 onNext 的发射
-
尝试打印
$event检查是否有任何错误发生并且未被捕获。顺便说一句,我强烈建议使用 (flows from)kotlinx.coroutines而不是 (observables from) rx,它更轻量级并且具有更好的 API。
标签: android c++ kotlin java-native-interface jniwrapper