Java 如何通过C++;在android中作为按钮的点击处理程序进行回调? 我正在构建一个Android应用程序,我需要从JNI部分动态创建UI元素,并将C++函数分配为点击处理程序。

Java 如何通过C++;在android中作为按钮的点击处理程序进行回调? 我正在构建一个Android应用程序,我需要从JNI部分动态创建UI元素,并将C++函数分配为点击处理程序。,java,android,c++,java-native-interface,Java,Android,C++,Java Native Interface,我定义了一个java函数来创建一个按钮并返回它。 我有一个C++函数,调用java函数并有按钮的JOBET。现在我想为这个对象分配另一个C++函数作为点击处理程序。 爪哇: C++: 在这个问题上 JNIpp库 已经引入了,并且它完全实现了我想要的,但是我想自己实现它,因为我不想在我的项目中添加那么多代码。此外,该库使用嵌套宏的复杂实现,使得它难以学习它的工作原理。 < P>使java对象对C++代码进行回调的过程几乎总是相同的;使java对象存储对本机对象(通常是指针)的某种引用,并将其传递回

我定义了一个java函数来创建一个按钮并返回它。 我有一个C++函数,调用java函数并有按钮的JOBET。现在我想为这个对象分配另一个C++函数作为点击处理程序。 爪哇:

C++:

在这个问题上 JNIpp库
已经引入了,并且它完全实现了我想要的,但是我想自己实现它,因为我不想在我的项目中添加那么多代码。此外,该库使用嵌套宏的复杂实现,使得它难以学习它的工作原理。

< P>使java对象对C++代码进行回调的过程几乎总是相同的;使java对象存储对本机对象(通常是指针)的某种引用,并将其传递回C++代码,该代码可以调用适当的函数。 潜在的实现可能如下所示:

MyOnClickListener.java

public class MyOnClickListener implements View.OnClickListener {
    private final long nativePeer;

    public MyOnClickListener(final long nativePeer) {
        this.nativePeer = nativePeer;
    }

    @Override
    public void onClick(View v) {
        OnClick(nativePeer);
    }

    @Override
    public void finalize() {
        Release(nativePeer);
    }

    private static native void OnClick(final long peer);
    private static native void Release(final long peer);
}
C++

extern "C" JNIEXPORT void Java_com_example_myapp_MyOnClickListener_OnClick(
        JNIEnv *env,
        jclass clazz,
        jlong nativePeer) {
    auto f = reinterpret_cast<std::function<void(void)>*>(nativePeer);
    (*f)();
}

extern "C" JNIEXPORT void Java_com_example_myapp_MyOnClickListener_Release(
        JNIEnv *env,
        jclass clazz,
        jlong nativePeer) {
    auto f = reinterpret_cast<std::function<void(void)>*>(nativePeer);
    delete f;
}

...

// Setting the OnClickListener

// We allocate this object with `new` since we need it to remain alive
// until the Java code no longer needs it. It is the responsibility of
// the Java code to ensure that the memory gets freed.
auto callback = new std::function<void(void)>([] {
    __android_log_print(ANDROID_LOG_WARN, "MyOnClickListener", "Hello from native onClick!");
});

jclass listener_clazz = env->FindClass("com/example/myapp/MyOnClickListener");
jmethodID new_listener = env->GetMethodID(listener_clazz, "<init>", "(J)V");
jobject listener = env->NewObject(listener_clazz, new_listener, callback);

jmethodID set_onclicklistener = env->GetMethodID(button_clazz, "setOnClickListener", "(Landroid/view/View$OnClickListener;)V");

env->CallVoidMethod(button, set_onclicklistener, listener);
extern“C”JNIEXPORT void Java\u com\u example\u myapp\u MyOnClickListener\u OnClick(
JNIEnv*env,
jclass clazz,
jlong nativePeer){
自动f=重新解释(本地对等);
(*f)();
}
外部“C”JNIEXPORT void Java\u com\u示例\u myapp\u MyOnClickListener\u发布(
JNIEnv*env,
jclass clazz,
jlong nativePeer){
自动f=重新解释(本地对等);
删除f;
}
...
//设置OnClickListener
//我们为这个对象分配'new',因为我们需要它保持活动状态
//直到Java代码不再需要它。这是我们的责任
//确保释放内存的Java代码。
自动回调=新的std::函数([]{
__android_log_print(android_log_警告,“MyOnClickListener”,“来自本机onClick的你好!”);
});
jclass listener_clazz=env->FindClass(“com/example/myapp/MyOnClickListener”);
jmethodID new_listener=env->GetMethodID(listener_clazz,“(J)V”);
jobject listener=env->NewObject(listener\u clazz,new\u listener,callback);
jmethodID设置了_onclicklistener=env->GetMethodID(按钮_clazz,“setOnClickListener”,“(Landroid/view/view$onclicklistener;)V”);
env->CallVoidMethod(按钮,设置\u onclicklistener,listener);

注意1:在实际代码中,您当然应该添加正确的错误处理,而不是盲目地假设每个JNI调用都成功

注意2:当您不再需要本机对等对象时,您可能希望显式调用
Release
函数,而不是依赖于要调用的
finalize


注3:在我的示例中,我使用了指向
std::function
的指针。您可能希望使用指向您自己的某个类的指针。这是由你来决定的。

< P>使java对象做回C++代码的过程总是相同的;使java对象存储对本机对象(通常是指针)的某种引用,并将其传递回C++代码,该代码可以调用适当的函数。 潜在的实现可能如下所示:

MyOnClickListener.java

public class MyOnClickListener implements View.OnClickListener {
    private final long nativePeer;

    public MyOnClickListener(final long nativePeer) {
        this.nativePeer = nativePeer;
    }

    @Override
    public void onClick(View v) {
        OnClick(nativePeer);
    }

    @Override
    public void finalize() {
        Release(nativePeer);
    }

    private static native void OnClick(final long peer);
    private static native void Release(final long peer);
}
C++

extern "C" JNIEXPORT void Java_com_example_myapp_MyOnClickListener_OnClick(
        JNIEnv *env,
        jclass clazz,
        jlong nativePeer) {
    auto f = reinterpret_cast<std::function<void(void)>*>(nativePeer);
    (*f)();
}

extern "C" JNIEXPORT void Java_com_example_myapp_MyOnClickListener_Release(
        JNIEnv *env,
        jclass clazz,
        jlong nativePeer) {
    auto f = reinterpret_cast<std::function<void(void)>*>(nativePeer);
    delete f;
}

...

// Setting the OnClickListener

// We allocate this object with `new` since we need it to remain alive
// until the Java code no longer needs it. It is the responsibility of
// the Java code to ensure that the memory gets freed.
auto callback = new std::function<void(void)>([] {
    __android_log_print(ANDROID_LOG_WARN, "MyOnClickListener", "Hello from native onClick!");
});

jclass listener_clazz = env->FindClass("com/example/myapp/MyOnClickListener");
jmethodID new_listener = env->GetMethodID(listener_clazz, "<init>", "(J)V");
jobject listener = env->NewObject(listener_clazz, new_listener, callback);

jmethodID set_onclicklistener = env->GetMethodID(button_clazz, "setOnClickListener", "(Landroid/view/View$OnClickListener;)V");

env->CallVoidMethod(button, set_onclicklistener, listener);
extern“C”JNIEXPORT void Java\u com\u example\u myapp\u MyOnClickListener\u OnClick(
JNIEnv*env,
jclass clazz,
jlong nativePeer){
自动f=重新解释(本地对等);
(*f)();
}
外部“C”JNIEXPORT void Java\u com\u示例\u myapp\u MyOnClickListener\u发布(
JNIEnv*env,
jclass clazz,
jlong nativePeer){
自动f=重新解释(本地对等);
删除f;
}
...
//设置OnClickListener
//我们为这个对象分配'new',因为我们需要它保持活动状态
//直到Java代码不再需要它。这是我们的责任
//确保释放内存的Java代码。
自动回调=新的std::函数([]{
__android_log_print(android_log_警告,“MyOnClickListener”,“来自本机onClick的你好!”);
});
jclass listener_clazz=env->FindClass(“com/example/myapp/MyOnClickListener”);
jmethodID new_listener=env->GetMethodID(listener_clazz,“(J)V”);
jobject listener=env->NewObject(listener\u clazz,new\u listener,callback);
jmethodID设置了_onclicklistener=env->GetMethodID(按钮_clazz,“setOnClickListener”,“(Landroid/view/view$onclicklistener;)V”);
env->CallVoidMethod(按钮,设置\u onclicklistener,listener);

注意1:在实际代码中,您当然应该添加正确的错误处理,而不是盲目地假设每个JNI调用都成功

注意2:当您不再需要本机对等对象时,您可能希望显式调用
Release
函数,而不是依赖于要调用的
finalize

注3:在我的示例中,我使用了指向
std::function
的指针。您可能希望使用指向您自己的某个类的指针。那真的要由你来决定