0%

Android JNI开发步骤二(native 调用java 方法)

在JNI代码中获取到了我们想要的值,需要返回到Java层,简单的情况下可以使用return某个值来实现。但是复杂情况下,我们需要不断地获取JNI中返回的值,我们就可以在JNI中主动去找Java中的方法,然后调用,并把JNI中的值作为Java方法的参数传入。如下:

//native方法将调用Java方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
JNIEXPORT void JNICALL nativeCallJava(JNIEnv *env, jobject thiz){
object_global = (jobject)env->NewGlobalRef(thiz);
JNIEnv *env = NULL;
//先获取JNIEnv
if (savedVm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6) != JNI_OK) {
env = NULL;
}
//再通过FindClass来加载当前需要的类
jclass clazz = env->FindClass("com/XXXX/jni/MainActivity");
//获取当前类中的静态方法
jmethodID method1 = env->GetStaticMethodID(clazz,"nativeCall","(Ljava/lang/String;)V");
jstring result = env->NewStringUTF("aaaaaaaaa");//字符串
env->CallStaticVoidMethod (clazz, method1,result);//调用静态方法
//获取普通成员方法
jmethodID method2 = env->GetMethodID(clazz,"nativeCall_nonStatic","(Ljava/lang/String;)V");
//调用成员方法,这个时候第一个参数应该是对象
env->CallVoidMethod (thiz, method2,result);
}

以上是借用JNI主动传进来的jobject ,它就代表对应的Java类的对象。然而有时候,我们没有这样的对象引用作为参数,就需要找到Java的对应的构造器获取Java类的一个对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
//调用java的静态方法
NIEXPORT void JNICALL callJavaStaticMethod (JNIEnv *env, jclass cls)
{
jclass clazz = NULL;
jstring str_arg = NULL;
jmethodID mid_static_method;
// 1、从classpath路径下搜索ClassMethod这个类,并返回该类的Class对象
clazz =(*env)->FindClass(env,"com/study/jnilearn/ClassMethod");
if (clazz == NULL) {
return;
}

// 2、从clazz类中查找callStaticMethod方法
mid_static_method = (*env)->GetStaticMethodID(env,clazz,"callStaticMethod","(Ljava/lang/String;I)V");
if (mid_static_method == NULL) {
printf("找不到callStaticMethod这个静态方法。");
return;
}

// 3、调用clazz类的callStaticMethod静态方法
str_arg = (*env)->NewStringUTF(env,"我是静态方法");
//调用Java的静态方法不需要Java类的对象。后面需要传入参数。
(*env)->CallStaticVoidMethod(env,clazz,mid_static_method, str_arg, 100);
// 删除局部引用
(*env)->DeleteLocalRef(env,clazz);
(*env)->DeleteLocalRef(env,str_arg);
}

/*
* 调用java的实例方法
*/
JNIEXPORT void JNICALL callJavaInstaceMethod (JNIEnv *env, jclass cls)
{
jclass clazz = NULL;
jobject jobj = NULL;
jmethodID mid_construct = NULL;
jmethodID mid_instance = NULL;
jstring str_arg = NULL;
// 1、从classpath路径下搜索ClassMethod这个类,并返回该类的Class对象
clazz = (*env)->FindClass(env, "com/study/jnilearn/ClassMethod");
if (clazz == NULL) {
printf("找不到'com.study.jnilearn.ClassMethod'这个类");
return;
}

// 2、获取类的默认构造方法ID ,没有参数
mid_construct = (*env)->GetMethodID(env,clazz, "<init>","()V");
if (mid_construct == NULL) {
printf("找不到默认的构造方法");
return;
}

// 3、查找实例方法的ID ,第三个参数传入java方法的名称。第四个是方法参数表达式
mid_instance = (*env)->GetMethodID(env, clazz, "callInstanceMethod", "(Ljava/lang/String;I)V");
if (mid_instance == NULL) {
return;
}

// 4、创建该类的实例
jobj = (*env)->NewObject(env,clazz,mid_construct);
if (jobj == NULL) {
printf("在com.study.jnilearn.ClassMethod类中找不到callInstanceMethod方法");
return;
}

// 5、调用对象的实例方法
str_arg = (*env)->NewStringUTF(env,"我是实例方法"); //创建字符串的方法
(*env)->CallVoidMethod(env,jobj,mid_instance,str_arg,200); //调用方法,需要传入参数

// 删除局部引用
(*env)->DeleteLocalRef(env,clazz);
(*env)->DeleteLocalRef(env,jobj);
(*env)->DeleteLocalRef(env,str_arg);

以上在创建Java类的对象的时候,调用的默认的无参数构造器,如果调用的是有参数的构造器,就需要一下写法:

1
2
3
4
5
6
7
8
9
//获取Student的jclass
jclass studentClass=env->FindClass("com/xxxx/Student");
//获取Student的构造方法ID
jmethodID studentCont=env->GetMethodID(studentClass,"<init>","(Ljava/lang/String;I)V");
//实例化Student并传递参数
jstring name = env->NewStringUTF("JIN 构造方法新建对象 宝强");
jint age=30;
//创建Student的对象,需要传入参数
jobject student= env->NewObject(studentClass,studentCont,name,age);