Overview
I continue to study JNI today. The first few articles have learned some basic content. Today we will practice all of them. This article is only for notes, in case you forget it in the future.
JNI access to the members of the Java object
Let's first look at the APIs that need to be used
Get jclass
jclass GetObjectClass(JNIEnv *env, jobject obj);
- jobject: object representing java
- The function returns a class object
Get jfieldID
jfieldID GetFieldID(JNIEnv *env, jclass clazz, const char *name, const char *sig);
- JNIEnv: JNIEnv pointer
- jclass: class object, which can be passed
GetObjectClass
orFindClass
obtained - name: the name of a variable in the class object
- sig: the type signature of the variable
- Return a variable of a class object, the type is jfieldID
Get the value of a variable
According to the type of variable, there will be different functions to get the value of the variable. The basic form of the function is as follows:
NativeType Get<type>Field(JNIEnv *env, jobject obj, jfieldID fieldID);
Function name | Return value type |
---|---|
GetBooleanField() | jboolean |
GetByteField() | jbyte |
GetCharField() | jchar |
GetShortField() | jshort |
GetIntField () | jit |
GetLongField() | jlong |
GetFloatField() | jfloat |
GetDoubleField() | jdouble |
GetObjectField() | jobject |
The first eight items are basic data types, and the ninth item is to get all reference data types
For example, get the int variable as follows:
jint GetIntField(JNIEnv * env, jobject obj, jfieldID fieldID);
- jobject: represents a java object
- jfieldID: on behalf of a class of variable, by
GetFieldID
acquiring - Return a jint
Set the value of the variable
According to the type of variable, there are different functions to set the value of the variable
void Set<type>Field(JNIEnv *env, jobject obj, jfieldID fieldID,
NativeType value);
Function name | Parameter Type |
---|---|
SetBooleanField() | jboolean |
SetByteField() | jbyte |
SetCharField () | jchar |
SetShortField() | jshort |
SetIntField() | jit |
SetLongField() | jlong |
SetFloatField() | jfloat |
SetDoubleField() | jdouble |
SetObjectField() | jobject |
The first eight items correspond to basic data types, and the ninth item corresponds to all reference types in java
For example, the function prototype of int
void setIntField(JNIEnv * env, jobject obj, jfieldID fieldID, jint value);
- value: You want to set the value of int, other parameters are the same as above, so I won’t repeat it
Get jmethodID
jmethodID GetMethodID(JNIEnv *env, jclass clazz,
const char *name, const char *sig);
- name: Get the name of the method in the class object
- sig: get the signature of the method
- Return value: If this method exists, return jmethodID, if it does not exist, return NULL
- If you get the java construction method, the value of const char *name and the value of parameter const char *sig are void(V)
Call object method
According to the return value of the java method, jni has different functions to call the method of the java object. There are three basic forms
NativeType Call<type>Method(JNIEnv *env, jobject obj,
jmethodID methodID, ...);
NativeType Call<type>MethodA(JNIEnv *env, jobject obj,
jmethodID methodID, const jvalue *args);
NativeType Call<type>MethodV(JNIEnv *env, jobject obj,
jmethodID methodID, va_list args);
The difference between these three methods is different from passing parameters, the most commonly used is the first one, we only talk about the first one
If the method returns an int, then the function prototype is
jint CallIntMethod(JNIEnv * env, jobject obj, jmethodID methodID, ...);
If the return value of the method is a reference data type
jobject CallObjectMethod(JNIEnv * env, jobject obj, jmethodID methodID, ...);
If the return value type of java is void
void CallVoidMethod(JNIEnv * env, jobject obj, jmethodID methodID, ...);
- jmethodID: method object, by
GetMethodID
obtaining - …: Variable parameters, the parameters you need to pass to the java method
Let's look at the complete code implemented below
First define a java class, which has a native method, which will be called when the object is created
public class Student {
public String name = "小红";
static {
System.loadLibrary("studentlib");
}
native void native_init();
public Student() {
native_init();
}
public void print() {
Log.d("mmm", name);
}
}
Register this java native method in jni, and then implement it in C
#include <jni.h>
#include <iostream>
#include <android/log.h>
static void native_init(JNIEnv *env, jobject jobject1) {
//1 获取java对象的变量的值,并重新为他设置新的值
//获取class对象
jclass jclass_student = env->GetObjectClass(jobject1);
//从class中获取变量
jfieldID jfieldId = env->GetFieldID(jclass_student, "name", "Ljava/lang/String;");
//从java对象obj中获取name变量的值
jstring name = static_cast<jstring>(env->GetObjectField(jobject1, jfieldId));
const char *char_name = env->GetStringUTFChars(name, JNI_FALSE);
//打印出原来的name变量的值
__android_log_print(ANDROID_LOG_INFO, "mmm", "method = %s, msg = %s", __FUNCTION__,
char_name);
const char native_name[] = "小明";
jstring jstring_name = env->NewStringUTF(native_name);
//通过jni重新设置变量name的值
env->SetObjectField(jobject1, jfieldId, jstring_name);
//2 调用java对象中的方法
//获取class对象中的print方法
jmethodID print = env->GetMethodID(jclass_student, "print", "()V");
//调用java对象中的print方法
env->CallVoidMethod(jobject1, print);
}
static const JNINativeMethod nativeMethod[] = {
{
"native_init", "()V", (void *) native_init},
};
static int registNativeMethod(JNIEnv *env) {
int result = -1;
jclass class_text = env->FindClass("com.taobao.alinnkit.ndk1.Student");
if (env->RegisterNatives(class_text, nativeMethod,
sizeof(nativeMethod) / sizeof(nativeMethod[0])) == JNI_OK) {
result = 0;
}
return result;
}
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
JNIEnv *env = NULL;
int result = -1;
if (vm->GetEnv((void **) &env, JNI_VERSION_1_1) == JNI_OK) {
if (registNativeMethod(env) == JNI_OK) {
result = JNI_VERSION_1_6;
}
return result;
}
}
Dynamic registration was mentioned in native_init
the last article, so I won’t say much here. The main implementation logic lies in the implementation. The general logic is to get the value Student
of the variable name
in the object and print it out, then reset name
the value of the variable, and finally call Student
Object print
method, print out name
the value of the variable
The last is to call, which can be triggered directly by new
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Student student = new Student();
}
Look at the print result
/mmm: method = native_init, msg = 小红
/mmm: 小明
JNI access to java static members
Let's take a look at the Api with the belt
FindClass
Get class object
jclass FindClass(JNIEnv *env, const char *name);
- const char *name: fully qualified class name
GetStaticFieldID
Get the static field of the class object
jfieldID GetStaticFieldID (JNIEnv *env,
jclass clazz,
const char *name,
const char *sig);
- name: the name of the static field
- sig: the type signature of the static field
GetStaticField
Get the value of the static field, according to the type of the static field, jni has different methods to get the value of the static field
Method name | return value |
---|---|
GetStaticBooleanField | jboolean |
GetStaticByteField | jbyte |
GetStaticCharField | jchar |
GetStaticShortField | jshort |
GetStaticIntField | jit |
GetStaticLongField | jlong |
GetStaticFloatField | jfloat |
GetStaticDoubleField | jdouble |
GetStaticObjectField | jobject |
Set the value of a static variable
void SetStatic<type>Field(JNIEnv *env,
jclass clazz,
jfieldID fieldID,
NativeType value);
- The last parameter is the value you need to set
Method name | NativeType |
---|---|
SetStaticBooleanField | jboolean |
SetStaticByteField | jbyte |
SetStaticCharField | jchar |
SetStaticShortField | jshort |
SetStaticIntField | jit |
SetStaticLongField | jlong |
SetStaticFloatField | jfloat |
SetStaticDoubleField | jdouble |
SetStaticObjectField | jobject |
Call static method
jmethodID GetStaticMethodID(jclass clazz, const char* name, const char* sig)
void CallStaticVoidMethod(jclass clazz, jmethodID methodID, ...)
These two are the same as the normal method used before, but the function name is changed.
Complete code
java code
public class Student {
public static String text = "没改过";
static {
System.loadLibrary("studentlib");
}
native void native_Text();
public static void printText() {
Log.d("mmm", text);
}
}
c code
static void native_text(JNIEnv *env, jobject jobject1) {
//获取class
jclass jclass_student = env->FindClass("com.taobao.alinnkit.ndk1.Student");
//获取静态变量text
jfieldID jfieldId_text = env->GetStaticFieldID(jclass_student, "text", "Ljava/lang/String;");
//获取静态变量text的值
jstring text = (jstring) env->GetStaticObjectField(jclass_student, jfieldId_text);
const char *char_name = env->GetStringUTFChars(text, JNI_FALSE);
__android_log_print(ANDROID_LOG_INFO, "mmm", "method = %s, msg = %s", __FUNCTION__,
char_name);
jstring jstring1 = env->NewStringUTF("改过了");
//修改静态变量text的值
env->SetStaticObjectField(jclass_student, jfieldId_text, jstring1);
//获取静态方法printText
jmethodID jmethodId = env->GetStaticMethodID(jclass_student, "printText", "()V");
//调用静态方法printText
env->CallStaticVoidMethod(jclass_student, jmethodId);
}
static const JNINativeMethod nativeMethod[] = {
{
"native_Text", "()V", (void *) native_text}
};
static int registNativeMethod(JNIEnv *env) {
int result = -1;
jclass class_text = env->FindClass("com.taobao.alinnkit.ndk1.Student");
if (env->RegisterNatives(class_text, nativeMethod,
sizeof(nativeMethod) / sizeof(nativeMethod[0])) == JNI_OK) {
result = 0;
}
return result;
}
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
JNIEnv *env = NULL;
int result = -1;
if (vm->GetEnv((void **) &env, JNI_VERSION_1_1) == JNI_OK) {
if (registNativeMethod(env) == JNI_OK) {
result = JNI_VERSION_1_6;
}
return result;
}
}
The main implementation is the native_text
method, mainly to obtain text
the value of the static variable, modify the value of the static variable text
, and call the static methodprintText
transfer
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Student student = new Student();
student.native_Text();
}
Print data
/mmm: method = native_text, msg = 没改过
/mmm: 改过了
reference
https://juejin.im/post/5d23fb066fb9a07eb15d7b29
https://blog.csdn.net/afei__/article/details/81016413
https://www.jianshu.com/p/67081d9b0a9c