昨天同事问我一个JNI问题,想从Native代码中返回一个Java对象,但是网上找的例子运行就崩溃了。仔细一想,我好想也没做过这样的操作,赶紧学习一下。
从Native层返回一个Java对象,有两种操作
- 传入一个创建好的Java对象,只在JNI代码中做赋值操作并返回
- 完全在JNI代码中新建一个对象,赋值并返回
创建一个Person类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public class Person { private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
|
Native方法
1 2 3 4
| public native Person getPerson(Person person);
public native Person getPerson2();
|
C++代码
方法1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| extern "C" JNIEXPORT jobject JNICALL Java_com_myapplication_MainActivity_getPerson(JNIEnv *env, jobject instance, jobject person) { jclass myClass = env->FindClass("com/myapplication/Person");
jfieldID name = env->GetFieldID(myClass, "name", "Ljava/lang/String;"); jfieldID age = env->GetFieldID(myClass, "age", "I");
env->SetObjectField(person, name, env->NewStringUTF("liuwei")); env->SetIntField(person, age, 20);
return person; }
|
方法2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| extern "C" JNIEXPORT jobject JNICALL Java_com_myapplication_MainActivity_getPerson2(JNIEnv *env, jobject instance) { jclass myClass = env->FindClass("com/myapplication/Person"); jmethodID id = env->GetMethodID(myClass, "<init>", "()V"); jobject person_ = env->NewObject(myClass, id); jfieldID name = env->GetFieldID(myClass, "name", "Ljava/lang/String;"); jfieldID age = env->GetFieldID(myClass, "age", "I");
env->SetObjectField(person_, name, env->NewStringUTF("liuwei")); env->SetIntField(person_, age, 20);
return person_; }
|
可以看到,方法1和方法2的代码区别就2行
1 2 3 4
| jmethodID id = env->GetMethodID(myClass, "<init>", "()V");
jobject person_ = env->NewObject(myClass, id);
|
在开发时 env->GetMethodID(myClass, "<init>", "()V");
很可能会在写代码是标红,提示无法找到<init>
,不需要理会,直接编译就好了。
调用
1 2 3 4 5 6 7 8 9 10
| TextView tv = findViewById(R.id.sample_text);
Person person = new Person();
getPerson(person);
tv.setText(person.getName() + " : " + getPerson2().getAge() );
|
搞定!又学习了一个知识点。
对了,同事代码崩溃的问题就是Java层用了方法2,但是JNI代码却用了方法1,没有创建出一个对象,导致崩溃。