android中关于jni调用java层方法的一些误导和见解

其实和c++中在全局函数调用某个对象的成员一样的,这个全局函数就是jni生成函数,而这个类是java中new出来的对象,不过有点不同,如下:

java code
------------------------------------
class JniApi{
     public static native void jni_test();
}
public class Test: extends Object{
     public void callback(){}
     public void CallJniTest(){JniApi.jni_test();}
}

c++ code

-----------------------------------
jvoid xxx_jni_test(JNIEnv *env,jclass jc){
 
jclass mJc = env->FindClass("xxx/Test");
//上面创建一个jclass 目的在于,传递进来的这个jc所引用的类实际上是JniApi类,我们要调用的java函数是在Test类中
jobject obj = env->AllocObject(mJc );
//创建一个类型为mJc类的实例对象
jmethodID methid = env->GetMethodID(mJc, "callback", "()V");
//获取这个方法在这个类中的id,其实说白了就和linux中container_of宏一样,求这个方法在这个类中的偏移,所以用到的是mJc,而不是obj
env->CallVoidMethod(obj,methid);
//最后调用方法,这个方法大概执行方式其实就是先得出对象obj的首地址,然后加上这个methid偏移,就能找到这个函数地址并执行了。
}

 

上面的例子其实是有问题的,callback函数确实是调用了,但并不是我们在java层中new出来的Test对象,而是jni中又重新new了一个,所以如果你在java层中用线程去监听这个函数里面的执行情况,那么你就知道有啥效果了。除非这个函数是一个静态函数,对所有实例都只有一份拷贝。
 
为了避免这种虚假的回调非成员函数,目前我想到的就一种:
1、修改jni_test参数,增加一个形式参数obj,即jni_test(Test obj);
2、在调用这个Jni的时候将this传入,类似于外部函数调用c++类中的方法一样,需要传入这个对象的指针或者引用。
修改后的代码如下:
java code
------------------------------------
class JniApi{
     public static native void jni_test(Test obj);
}
public class Test: extends Object{
     public void callback(){}
     public void CallJniTest(){JniApi.jni_test(this);}
}

 

c++ code
-----------------------------------
jvoid xxx_jni_test(JNIEnv *env,jclass jc, jobject obj){
 
jclass mJc = env->GetObjectClass(obj)
//获取这个实例对象具体属于的类
jmethodID methid = env->GetMethodID(mJc, "callback", "()V");
//得到偏移
env->CallVoidMethod(obj,methid);
}

 

这样,就能保证调用到的是你在java中new出来的对象中的函数了。
posted @ 2013-04-03 16:37  凡人修行  阅读(1274)  评论(0编辑  收藏  举报