JNI里面调用Java,JNI非JAVA线程里面调用Java方法

1 篇文章 0 订阅


            最近在开发android时由于一些功能需要在JNI里面实现,然后在C++/C里面调用Java里面的方法(相当于CallBack之类的),发现在C++/C的线程里面调用Java里面的方法的资料非常少,网上的博客也是差不多一样的(国内的技术博客都是差不多的,甚至连作者都没有去实现一下),现在做个记录:

  在C++/C代码中调用Java的方法,大致的方法就是 :①找到类(FindClass),②找到方法(GetMethodID),③调用(CallVoidMethod   or CallStaticXXMethod),但是有两种不同的场景

1、C++/C在Java线程中调用JAVA类里面的方法

                先解释一下: C++/C在Java线程中调用JAVA类里面的方法,就是这个方法的写法是:
JNIEXPORT jint JNICALL Java_com_example_testjni_Hunter_test(JNIEnv *env, jclass obj,jstring str){
   return 0;
}

</pre>                 这个方法就相当于一个接口,提供给Java调用。这个方法中我们得到了  <span style="background-color: rgb(240, 240, 240);">JNIEnv 和jclass所以调用Java代码里面的方法也极其简单,直接上代码</span></div><div><span style="background-color: rgb(240, 240, 240);"><span style="white-space:pre">		</span></span><pre name="code" class="cpp">JNIEXPORT jint JNICALL Java_com_example_testjni_Hunter_test(JNIEnv *env, jclass obj,jstring str){
	    // 注意C++和C代码中env的写法。 不要说博主的博客复制都有错啊!!!!!!!!
		// .cpp 文件是C++代码,博主现在就是C++代码
		// 如果是C代码,那么写法是  jclass test = (*env)->FindClass(env,"com/example/testjni/Hunter");
	    //因为有了  JNIEnv和jclass。调用比较方便
	    //1 . 找到java代码的 class文件
	    jclass test = env->FindClass("com/example/testjni/Hunter");// 参数就是java类的路径加上名字
	    if(test==0){
	       // 找不到类,写错了??注意包名,类名
	        return -1;
	    }
	    
	    
	    //2 寻找class里面的方法。。参数①:类名的引用,②准备调用Java类里面方法的名字,
	    //③括号里面表示方法的要传入的参数类型,现在是空的
	    // 括号外面  V   表示这个方法的返回值是  void  类型的
	    jmethodID method1 = env->GetMethodID(test,"helloFromJava","()V"); 
	    if(method1==0){
	    	 // 找不到类,写错了??注意方法的名字
	        return -1;
	    }
	    // 例子 :如果参数是一个 整形的怎么写???注意括号里面的  I 
	    // 就这样  jmethodID method1 = env->GetMethodID(test,"helloFromJava","(I)V"); 
	    
	    // 终于找到了。。。
	    //3 .调用这个方法, 
	    // 参数说明  ②为方法的名字,如果有参数记得在后面填上,
	    env->CallVoidMethod(obj,method1);
	    
	    // 例子 :如果参数是一个 整形的怎么写???
	    // 就这样   env->CallVoidMethod(obj,method1,10); // 10就是要传到Java 方法里面的参数
   return 0;
}
note:注意JNI里面C++代码和C代码的区别

2、JNI在新起的线程中调用JAVA类里面的方法

JNI在新起的线程中调用JAVA类里面的方法 解释一下:就是我新开了一个线程,里面没有 JNIEnv和jclass。怎么办?有人会说,保存到全局变量去,嗯,确实有道理,但是在新开的线程里面,就算保存了 JNIEnv和jclass,直接调用也是会抛异常的。其实我的做法也是保存到全局变量中,只不过不是保存他们,而是JavaVM和jobject
代码:
static JavaVM *gs_jvm = NULL; // 保存起来
static jobject gs_object = NULL; // 保存起来

JNIEXPORT jint JNICALL Java_com_example_testjni_Hunter_test(JNIEnv *env,
		jclass obj) {
	// 注意了,在第一次进来的时候,我就保存他们了,要快!!!!
	env->GetJavaVM(&gs_jvm); //保存到全局变量中JVM   
	gs_object = env->NewGlobalRef(obj);
	return 0;
}

/* 服务器发送过来的消息到达了 */
int frecvMsg_callback() {
	// 注意!!我要调用了
	JNIEnv *env;
	// 获取当前线程的 env 
	gs_jvm->AttachCurrentThread((void **) &env, NULL);
	// 这个class默认是初始化gs_object时所调用的Java 类
	jclass cls = env->GetObjectClass(gs_object);
	// 开始对讲消息------
	jmethodID mid = env->GetMethodID(cls, "startTalkback", "(I)V");
	if (mid == NULL) {
		return -1;
	}
	// 调用
	env->CallVoidMethod(gs_object, mid, 1);
	// 用完之后一定要  DetachCurrentThread 取消关联,要不然程序退出会有异常
	(gs_jvm)->DetachCurrentThread();
	return 0;
}

note:用完之后记得
DetachCurrentThread
<span style="font-weight: bold; white-space: pre;">	</span>Ok.先写到这里。这样我们就可以在C++/c里面随便调用Java方法了。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值