对于JNI的基本使用请移步:Hello JNI
本文主要介绍以下几个函数的使用:
GetObjectClass
GetFieldID,GetStaticFieldID
Get< Type>Field,GetStatic< Type>Field
Set< Type>Field,SetStatic< Type>Field
案例介绍:通过JNI获取并修改Java中类的变量值
本文也是基于上面的代码继续添加:
JniDemo中添加name,age变量,和accessField(),accessStaticField()方法。
public class JniDemo {
//路径:/JNIDemo/app/build/intermediates/classes/debug/com/test/git/jnidemo/JniUtil/JniDemo.class
public String name = "Lucy";
public static int age = 10;
public native String helloJni();
//修改字段值
public native void accessField();
//修改字段值(静态方法)
public native void accessStaticField();
static {
System.loadLibrary("NdkJniDemo");
}
}
生成相应的头文件:
JNIEXPORT void JNICALL Java_com_test_git_jnidemo_JniUtil_JniDemo_accessField
(JNIEnv *, jobject);
JNIEXPORT void JNICALL Java_com_test_git_jnidemo_JniUtil_JniDemo_accessStaticField
(JNIEnv *, jobject);
JniDemo.cpp
通过JNI获取并修改Java中变量值
对于变量的签名可以参考:JNI类型
JNIEXPORT void JNICALL Java_com_test_git_jnidemo_JniUtil_JniDemo_accessField
(JNIEnv *env, jobject obj){
//1.获取jclass obj是JniDemo对象, JNIDemo.class
jclass cls = (*env).GetObjectClass(obj);
//2.获取jfieldID
//name:属性名称,sig:属性签名
//jfieldID GetFieldID(jclass clazz, const char* name, const char* sig)
jfieldID fid = (*env).GetFieldID(cls, "name", "Ljava/lang/String;");
//3.修改name的值
//a.获取name属性的值 Get<Type>Field
jstring jstr = (jstring) (*env).GetObjectField(obj, fid);
//b.jstring转成c字符串
//isCopy:true复制, false不复制,或者NULL
//const char* GetStringUTFChars(jstring string, jboolean* isCopy)
const char* c_str = (*env).GetStringUTFChars(jstr, JNI_FALSE);
//c.拼接得到新的字符串
char new_char[40] = "changed ";
//复制c_str 到 new_char
strcat(new_char, c_str);
//d.c字符串转换成String
jstring new_jstr = (*env).NewStringUTF(new_char);
//e.修改name值
//Set<Type>Field
(*env).SetObjectField(obj, fid, new_jstr);
//释放资源
(*env).ReleaseStringUTFChars(jstr, c_str);
};
通过JNI获取并修改Java中静态变量值
JNIEXPORT void JNICALL Java_com_test_git_jnidemo_JniUtil_JniDemo_accessStaticField
(JNIEnv *env, jobject obj){
//1.获取jclass
jclass cls = env->GetObjectClass(obj);
//2.获取age的jfieldID 注意用GetStaticFieldID方法
jfieldID jfid = env->GetStaticFieldID(cls, "age", "I");
//3.通过jfid获取age的属性值,注意用GetStaticIntField
jint jage = env->GetStaticIntField(cls, jfid);
jage ++;
//4.修改age的属性值,注意用GetStaticIntField
env->SetStaticIntField(cls,jfid, jage);
};
MainActivity调用
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity-";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
JniDemo jd = new JniDemo();
Log.i(TAG, "helloJni->" + jd.helloJni());
Log.i(TAG, "name修改前: " + jd.name);
jd.accessField();
Log.i(TAG, "name修改后: " + jd.name);
Log.i(TAG, "age修改前: " + jd.age);
jd.accessStaticField();
Log.i(TAG, "age修改后: " + jd.age);
}
}
执行结果:
09-24 12:32:44.021 19457-19457/com.test.git.jnidemo I/MainActivity-: helloJni->hello jni
09-24 12:32:44.021 19457-19457/com.test.git.jnidemo I/MainActivity-: name修改前: Lucy
09-24 12:32:44.021 19457-19457/com.test.git.jnidemo I/MainActivity-: name修改后: changed Lucy
09-24 12:32:44.021 19457-19457/com.test.git.jnidemo I/MainActivity-: age修改前: 11
09-24 12:32:44.021 19457-19457/com.test.git.jnidemo I/MainActivity-: age修改后: 12
扩展
JNI获取并修改Java中Array的值
JniDemo.class
public String[] courses = {"语文", "数学"};
public native void accessArrayField();
com_test_git_jnidemo_JniUtil_JniDemo.h头文件
JNIEXPORT void JNICALL Java_com_test_git_jnidemo_JniUtil_JniDemo_accessArrayField
(JNIEnv *, jobject);
JniDemo.cpp
JNIEXPORT void JNICALL Java_com_test_git_jnidemo_JniUtil_JniDemo_accessArrayField
(JNIEnv *env, jobject jobj){
jclass cls = env->GetObjectClass(jobj);
jfieldID fid = env->GetFieldID(cls, "courses", "[Ljava/lang/String;");
jobjectArray jarray = (jobjectArray) env->GetObjectField(jobj, fid);
env->SetObjectArrayElement(jarray, 0, env->NewStringUTF("英语"));
};
MainActivity.java
Log.i(TAG, "courses修改前: " + jd.courses[0]);
jd.accessArrayField();
Log.i(TAG, "courses修改后: " + jd.courses[0]);
打印结果:
09-24 14:36:23.041 18001-18001/com.test.git.jnidemo I/MainActivity-: courses修改前: 语文
09-24 14:36:23.042 18001-18001/com.test.git.jnidemo I/MainActivity-: courses修改后: 英语