使用 C++ 实现 Android 事件处理程序

2024-03-08

我有一个 Java 布局设计,目前正在通过 JNI 移植到 C++。我实际上已经完成了这一点,但我目前对如何设置事件处理程序(例如 setOnClickListener)感到困惑。我已经经历过JNI规范 https://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/functions.html#wp17314并没有得到太多的运气。

如果有人可以将以下代码片段移植到 C++ 或引导我走向正确的方向(由于结果的代码量而更合理),我将不胜感激。

    public void setOnClickListener(boolean modification, int index, int commandIndex, final TextView textView){
        final int key = index;
        final int command = commandIndex;
        if(modification) {
            textView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    changingMenu(key, command, textView);
                    Runnable r = new Runnable() {
                        @Override
                        public void run() {
                            resetMenu(key, command, textView);
                        }
                    };

                    Handler h = new Handler();
                    h.postDelayed(r, 250);
                }
            });
            return;
        }
        menuTitle.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                toggleMenu();
            }
        });
    }

EDIT: 将错误的参数传递给 setOnClickListener

Java

Object getProxy (MyInvocationHandler mih) {
    ClassLoader classLoader = new ClassLoader() {
        @Override
        public Class<?> loadClass(String name) throws ClassNotFoundException {
            return super.loadClass(name);
        }
    };
    return java.lang.reflect.Proxy.newProxyInstance(classLoader, new Class[] {  }, mih);
}

C++

jobject createProxyInstance(JNIEnv *env, jclass cls, CFunc cfunc) {
    jclass cls_IH = env->FindClass("com/app/core/MyInvocationHandler");
    jmethodID cst_IH = env->GetMethodID(cls_IH, "<init>", "(J)V");
    jobject myIH = env->NewObject(cls_IH, cst_IH, (jlong)cfunc);

    jclass klass = env->FindClass("com/app/core/Activity");
    jmethodID method = env->GetMethodID(klass, "getProxy", "(Lcom/app/core/MyInvocationHandler;)Ljava/lang/Object;");
    return env->CallObjectMethod(context, method, myIH); //Returning wrong object?
}

jobject aa (JNIEnv *env, jobject obj, jobject proxy, jobject method, jobjectArray args) {
    __android_log_print(ANDROID_LOG_ERROR, "TEST", "SUCCESS");
}

void setListeners() {
    jclass klass = env->FindClass("android/view/View");
    jmethodID method = env->GetMethodID(klass, "setOnClickListener", "(Landroid/view/View$OnClickListener;)V");
    klass = env->FindClass("android/view/View$OnClickListener");
    env->CallVoidMethod(imageView, method, createProxyInstance(env, klass, &aa));
}

您显示的语法归结为在编译时创建匿名内部类,并插入调用来创建这些类的对象(在范围内具有正确的变量)来代替new View.OnClickListener() { ... }表达。

我看到以下两个选项:

  • 对于每个不同的接口,您创建一个实现该接口的小型 Java 类,其中包含native接口方法的实现。这是最直接的方法,但它确实需要您保持数十或数百个接口实现的直接性。

  • You use java.lang.reflect.Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)动态创建实现必要接口的对象。这会将每个方法调用重新路由到您的InvocationHandler实现,它应该是一个具有native Object invoke(Object proxy, Method method, Object[] args)执行。

    为了使所有这些都可重用,您可以实现这个InvocationHandler包裹一个std::function对象,所以最终调用egmenuTitle.setOnClickListener可能如下所示:

env->CallVoidMethod(menuTitle, menuTitle_setOnClickListener,
 createProxyInstance(env, cls_View_OnClickListener, [](JNIEnv *env, jobject proxy, jobject method, jobjectArray args) {
   ... 
});

对于后一种解决方案,定义以下 Java 类:

class MyInvocationHandler implements InvocationHandler {
  private long cfunc;
  MyInvocationHandler(long cfunc) { this.cfunc = cfunc; }
  public native static Object invoke(Object proxy, Method method, Object[] args);
}

您在 C++ 端实现为:

typedef jobject (*CFunc)(JNIEnv *env, jobject obj, jobject proxy, jobject method, jobjectArray args)
extern "C" jobject Java_MyInvocationHandler_invoke(JNIEnv *env, jobject obj, jobject proxy, jobject method, jobjectArray args) {
  jclass cls_myIH = env->GetObjectClass(obj);
  jfieldID fld_myIH_cfunc = env->GetFieldID(cls_myIH, "cfunc", "J");
  CFunc cfunc = (CFunc)env->GetLongField(obj, fld_myIH_cfunc);
  cfunc(env, proxy, method, args);
  return nullptr;
}

最后我们可以实现createProxyInstance如下:

jobject createProxyInstance(JNIEnv *env, jclass cls, CFunc cfunc) {
  jclass cls_IH = env->GetClass("MyInvocationHandler");
  jmethodID cst_IH = env->GetMethodID(cls_ID, "<init>", "(J)V");
  jobject myIH = env->NewObject(cls_ID, cst_IH, (jlong)cfunc);

  // now call Proxy.createProxyInstance with this object as InvocationHandler
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 C++ 实现 Android 事件处理程序 的相关文章

随机推荐

  • OrientDB性能

    我一直在阅读有关 OrientDB 性能基准的帖子 http technet weblineindia com web introduction to orientdb a nosql dbms http technet weblinein
  • 蚀。将类型层次结构复制到剪贴板

    When I open Type Hierarchy in Eclipse either F4 or Ctrl T is there any way to copy the result tree as text into the clip
  • Rails:simple_form:从复选框集合中获取空字符串

    我的观点中有以下代码 每当我提交表单时 我都会得到类似的值 admin moderator 但我期待类似的事情 admin moderator 为什么是这样 此外 我做了一个检查元素 并且有一个
  • 为什么没有纯 Python SSH1(版本 1)客户端实现?

    似乎有一些很好的纯 Python SSH2 客户端实现 但我还没有找到一个适用于 SSH1 的客户端 除了对这样的项目缺乏兴趣之外 还有什么具体原因吗 我完全意识到许多 SSH1 漏洞 但是对于我们这些想要编写 SSH 客户端来管理仅支持
  • 反应本机滚动视图不会从文本输入内部滚动

    我在滚动视图中添加了多文本输入 问题是当我想从文本输入内部向下滚动时 我将手指放在文本输入内部并向下滚动 但它没有向下滚动页面 有没有办法解决这个问题 这是示例代码 export default class ScrollViewWithTe
  • 根据尺寸类别更改约束乘数

    是否可以根据当前的尺寸类别为约束赋予不同的乘数 我的观点是 对于常规尺寸类宽度 我希望其尺寸为屏幕尺寸的一半 对于紧凑尺寸类宽度 我希望其尺寸为屏幕尺寸的 80 在故事板中 我可以选择将不同大小类别的不同变量添加到约束常量值中 但不能添加它
  • 如何更新vcpkg本身?

    我已经安装了 vcpkg 一个 C 包管理器 现在过了一段时间 我想更新一下 我怎样才能做到这一点 我需要卸载并重新安装吗 更新 vcpkg git 克隆的最佳方法是 将所有已安装端口的列表保存在某处 git pull 删除
  • geom_histogram:错误的垃圾箱?

    我正在使用 ggplot 2 1 0 来绘制直方图 并且我对直方图箱有意外的行为 我在这里举了一个左封闭 bin 的示例 即 0 0 1 binwidth 为 0 1 mydf lt data frame myvar c 1 0 5 0 4
  • 有没有更好的方法来打印cout最多N个字符的字符串?

    编辑 我发送的是二进制文件而不是字符串 我的测试是使用 html 页面 所以在这个例子中我只使用一个字符串 但我的问题是关于二进制 向量和使用 ostream 进行调试 我这样做可以消除一些混乱 我有以下代码 cout lt lt stri
  • 以 Django 形式访问 POST 数据

    我一直在使用这个网站 http jacobian org writing dynamic form generation 作为如何在 Django 中制作动态表单的示例 在他看来 他使用 if request method POST for
  • 在unity3D android中本地保存大量数据的最佳方法? [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我正在开发一个2D游戏 稍后将用作摊位的广告活动 我需要存储用户信息 姓名 号码 电子邮件和分数 这些
  • java servlet:请求参数包含加号

    请求参数就像decrypt param 5FHjiSJ6NOTmi7 2tnnkQ 在 servlet 中 当我尝试通过以下方式打印参数时String param request getParameter param I get 5FHji
  • javascript 点击事件处理程序在没有点击的情况下触发

    为什么在没有单击指定按钮的情况下会触发此函数 我查看了一些类似的问题 但没有一个涉及此代码结构 可能是我丢失的明显原因 document getElementById main btn addEventListener click hide
  • 如何在 CSS 中设置背景图像不透明度而不使用伪之前/之后和/或定位的 div

    我有一个由 CMS 生成的 div 其中包含一个背景图像 我想更改该背景图像的不透明度 而不影响该 div 子元素的不透明度 https jsfiddle net L5b81yqo https jsfiddle net L5b81yqo H
  • PyCharm 和 VirtualEnvs - 如何删除旧版本

    如何从 PyCharm 中删除遗留项目的所有痕迹 背景 我今天从 PyCharm 社区版升级到 PyCharm 专业版 原因是这样我就可以从事 Django 项目 特别是一个名为 deals 的新兴遗留项目 我删除了旧项目文件夹 然后 我打
  • Ember JS/Handlebars 视图助手

    目前 如果我们将视图定义为 view App myView ember handlebars 会将视图元素包裹在一个 div class ember view 有办法阻止这种情况吗 您可能想将 tagName 设置为 App MyView
  • “无法从安装目录获取安装脚本的一致路径”

    我正在使用 pip 从 git 存储库安装包 pip install e git git github com knipknap SpiffWorkflow git master egg SpiffWorkflow dev 克隆存储库没有问
  • 如何编写一个 C++ 程序来过滤掉非整数?

    像这样的东西 cout lt lt Enter the number of columns cin gt gt input while input int cout lt lt endl lt lt Column size must be
  • 偏移日期时间解析

    需要从格式解析日期时间2016 06 24T13 39 44 687680 第一步使用 尝试用线路解析没有微秒的时间 System out println OffsetDateTime parse 2011 12 03T10 15 30 D
  • 使用 C++ 实现 Android 事件处理程序

    我有一个 Java 布局设计 目前正在通过 JNI 移植到 C 我实际上已经完成了这一点 但我目前对如何设置事件处理程序 例如 setOnClickListener 感到困惑 我已经经历过JNI规范 https docs oracle co