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

本教程将介绍使用C++实现Android事件处理程序的处理方法,这篇教程是从别的地方看到的,然后加了一些国外程序员的疑问与解答,希望能对你有所帮助,好了,下面开始学习吧。

使用C++实现Android事件处理程序 教程 第1张

问题描述

我有一个用Java编写的布局设计,目前正在通过JNI移植到C++。在这一点上,我实际上已经完成了,但是我目前对于怎么设置事件处理程序(例如setOnClickListener)感到困惑。我已经经历了the JNI specification,运气不太好。

如果有人能将下面的代码片段移植到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();
}
  });
 }

编辑:

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);
}

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。这是最直接的方法,但它确实要求您保持数十或数百个接口实现的直截了当。

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

    要使所有这些都可重用,您可以实现thisInvocationHandler来包装std::function对象,这样对egemenuTitle.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
}

好了关于使用C++实现Android事件处理程序的教程就到这里就结束了,希望趣模板源码网找到的这篇技术文章能帮助到大家,更多技术教程可以在站内搜索。