Android jni/ndk编程三:native访问java
一.访问静态字段
Java层的field和method,不管它是public,还是package、private和protected,从
JNI都可以访问到,Java面向语言的封装性不见了。
静态字段和非静态的字段访问方式不同,jni规范提供了一系列带static标示的访问静态字段的函数:
jobject (*GetStaticObjectField)(JNIEnv*, jclass, jfieldID);
jboolean (*GetStaticBooleanField)(JNIEnv*, jclass, jfieldID);
jbyte (*GetStaticByteField)(JNIEnv*, jclass, jfieldID);
jchar (*GetStaticCharField)(JNIEnv*, jclass, jfieldID);
jshort (*GetStaticShortField)(JNIEnv*, jclass, jfieldID);
jint (*GetStaticIntField)(JNIEnv*, jclass, jfieldID);
jlong (*GetStaticLongField)(JNIEnv*, jclass, jfieldID);
jfloat (*GetStaticFloatField)(JNIEnv*, jclass, jfieldID) __NDK_FPABI__;
jdouble (*GetStaticDoubleField)(JNIEnv*, jclass, jfieldID) __NDK_FPABI__;
void (*SetStaticObjectField)(JNIEnv*, jclass, jfieldID, jobject);
void (*SetStaticBooleanField)(JNIEnv*, jclass, jfieldID, jboolean);
void (*SetStaticByteField)(JNIEnv*, jclass, jfieldID, jbyte);
void (*SetStaticCharField)(JNIEnv*, jclass, jfieldID, jchar);
void (*SetStaticShortField)(JNIEnv*, jclass, jfieldID, jshort);
void (*SetStaticIntField)(JNIEnv*, jclass, jfieldID, jint);
void (*SetStaticLongField)(JNIEnv*, jclass, jfieldID, jlong);
void (*SetStaticFloatField)(JNIEnv*, jclass, jfieldID, jfloat) __NDK_FPABI__;
void (*SetStaticDoubleField)(JNIEnv*, jclass, jfieldID, jdouble) __NDK_FPABI__;
访问流程:
- 获得java层的类:jclass cls = (*env)->GetObjectClass(env, obj);
- 获得字段的ID:jfieldID fid = (*env)->GetStaticFieldID(env, cls, “s”, “Ljava/lang/String;”);
- 获得字段的值:jstring jstr = (*env)->GetStaticObjectField(env, cls, fid);
- 设置字段的值:(*env)->SetStaticObjectField(env, cls, fid, jstr);
按照以上的流程,参照上面访问静态字段的函数定义,写如下测试代码:
void native_accessJava(JNIEnv * env, jobject obj){
LOGE("lstr:native_accessJava");
//1. 获得java层的类:jclass cls = (*env)->GetObjectClass(env, obj);
jclass cls = (*env)->GetObjectClass(env, obj);
//2. 获得字段的ID:jfieldID fid = (*env)->GetStaticFieldID(env, cls, "s", "Ljava/lang/String;");
jfieldID fid = (*env)->GetStaticFieldID(env, cls, "s", "Ljava/lang/String;");
if (fid == NULL) {
LOGE("get feild id error");
return; /* failed to find the field */
}
//3. 获得字段的值:jstring jstr = (*env)->GetStaticObjectField(env, cls, fid);
jstring jstr = (*env)->GetStaticObjectField(env, cls, fid);
LOGE("lstr:native_accessJava");
const char * lstr = (*env)->GetStringUTFChars(env,jstr,NULL);
LOGE("lstr: %s",lstr);
(*env)->ReleaseStringUTFChars(env,jstr,lstr);
//4. 设置字段的值:(*env)->SetStaticObjectField(env, cls, fid, jstr);
jstr = (*env)->NewStringUTF(env, "jni set");
if (jstr == NULL) {
return; /* out of memory */
}
(*env)->SetStaticObjectField(env, cls, fid, jstr);
}
注册方法的数组:
static JNINativeMethod gMethods[] = {
{"sayHello", "([I)I", (void *)native_sayHello},
{"arrayTry","([Ljava/lang/String;)[Ljava/lang/String;",(void *)native_arrayTry},
{"accessJava","()V",(void *)native_accessJava},
};
java中访问的代码:
public class MainActivity extends AppCompatActivity {
TextView textView = null;
static String s = "java str";
static {
System.loadLibrary("hello");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.text);
accessJava();
textView.setText(s);
}
public native int sayHello(int []arr);
public native String[] arrayTry(String [] arr);
public native void accessJava();
}
在jni代码所在目录执行adk-build命令,把编译生成的libhello.so文件拷贝到Android工程的jniLibs目录下,运行android程序即可看到现象。
二.访问实例字段
有了访问静态字段的经历,在去写访问实例字段的代码就简单多了,这里总结下使用流程:
- 获得java层的类:jclass cls = (*env)->GetObjectClass(env, obj);
- 获得字段的ID:jfieldID fid = (*env)->GetFieldID(env, cls, “ss”, “Ljava/lang/String;”);
- 获得字段的值:jstring jstr = (*env)->GetObjectField(env, obj, fid);
- 设置字段的值:(*env)->SetObjectField(env, obj, fid, jstr);
在写代码之前,先看一下jni.h中定义的访问实例字段的函数:
jfieldID (*GetFieldID)(JNIEnv*, jclass, const char*, const char*);
jobject (*GetObjectField)(JNIEnv*, jobject, jfieldID);
jboolean (*GetBooleanField)(JNIEnv*, jobject, jfieldID);
jbyte (*GetByteField)(JNIEnv*, jobject, jfieldID);
jchar (*GetCharField)(JNIEnv*, jobject, jfieldID);
jshort (*GetShortField)(JNIEnv*, jobject, jfieldID);
jint (*GetIntField)(JNIEnv*, jobject, jfieldID);
jlong (*GetLongField)(JNIEnv*, jobject, jfieldID);
jfloat (*GetFloatField)(JNIEnv*, jobject, jfieldID) __NDK_FPABI__;
jdouble (*GetDoubleField)(JNIEnv*, jobject, jfieldID) __NDK_FPABI__;
void (*SetObjectField)(JNIEnv*, jobject, jfieldID, jobject);
void (*SetBooleanField)(JNIEnv*, jobject, jfieldID, jboolean);
void (*SetByteField)(JNIEnv*, jobject, jfieldID, jbyte);
void (*SetCharField)(JNIEnv*, jobject, jfieldID, jchar);
void (*SetShortField)(JNIEnv*, jobject, jfieldID, jshort);
void (*SetIntField)(JNIEnv*, jobject, jfieldID, jint);
void (*SetLongField)(JNIEnv*, jobject, jfieldID, jlong);
void (*SetFloatField)(JNIEnv*, jobject, jfieldID, jfloat) __NDK_FPABI__;
void (*SetDoubleField)(JNIEnv*, jobject, jfieldID, jdouble) __NDK_FPABI__;
可以看到访问实例字段的函数和访问静态字段的函数在名字上就有区别,而且一定要注意的是,访问实例字段函数的第三个参数是jobject,是一个对象,而访问静态字段的第三个参数是jclass,是一个类。
我们使用上面给出的函数和我们总结的使用流程写如下代码:
void native_accessinstanceJava(JNIEnv * env, jobject obj){
LOGE("lstr:native_accessinstanceJava");
//1. 获得java层的类:jclass cls = (*env)->GetObjectClass(env, obj);
jclass cls = (*env)->GetObjectClass(env, obj);
//2. 获得字段的ID:jfieldID fid = (*env)->GetFieldID(env, cls, "ss", "Ljava/lang/String;");
jfieldID fid = (*env)->GetFieldID(env, cls, "ss", "Ljava/lang/String;");
if (fid == NULL) {
LOGE("get feild id error");
return; /* failed to find the field */
}
//3. 获得字段的值:jstring jstr = (*env)->GetObjectField(env, cls, fid);
jstring jstr = (*env)->GetObjectField(env, obj, fid);
const char * lstr = (*env)->GetStringUTFChars(env,jstr,NULL);
LOGE("lstr: %s",lstr);
(*env)->ReleaseStringUTFChars(env,jstr,lstr);
//4. 设置字段的值:(*env)->SetObjectField(env, cls, fid, jstr);
jstr = (*env)->NewStringUTF(env, "jni set");
if (jstr == NULL) {
return; /* out of memory */
}
(*env)->SetObjectField(env, obj, fid, jstr);
}
注册方法的数组:
static JNINativeMethod gMethods[] = {
{"sayHello", "([I)I", (void *)native_sayHello},
{"arrayTry","([Ljava/lang/String;)[Ljava/lang/String;",(void *)native_arrayTry},
{"accessJava","()V",(void *)native_accessJava},
{"accessinstanceJava","()V",(void *)native_accessinstanceJava},
};
JNI_OnLoad等方法请参考之前的博客。
java层调用很非常简单,这里就不贴了。
三.访问静态方法
静态方法的访问总结为两步:
• 首先通过GetStaticMethodID在给定类中查找方法
如:jmethodID mid = (*env)->GetStaticMethodID(env,cls,”changeStr”,”()V”);
• 通过CallStaticMethod调用
如:(*env)->CallStaticVoidMethod(env, cls, mid);
jni中定义的访问静态方法的函数有如下一些:
jmethodID (*GetStaticMethodID)(JNIEnv*, jclass, const char*, const char*);
jobject (*CallStaticObjectMethod)(JNIEnv*, jclass, jmethodID, ...);
jobject (*CallStaticObjectMethodV)(JNIEnv*, jclass, jmethodID, va_list);
jobject (*CallStaticObjectMethodA)(JNIEnv*, jclass, jmethodID, jvalue*);
jboolean (*CallStaticBooleanMethod)(JNIEnv*, jclass, jmethodID, ...);
jboolean (*CallStaticBooleanMethodV)(JNIEnv*, jclass, jmethodID,va_list);
jboolean (*CallStaticBooleanMethodA)(JNIEnv*, jclass, jmethodID, jvalue*);
jbyte (*CallStaticByteMethod)(JNIEnv*, jclass, jmethodID, ...);
jbyte (*CallStaticByteMethodV)(JNIEnv*, jclass, jmethodID, va_list);
jbyte (*CallStaticByteMethodA)(JNIEnv*, jclass, jmethodID, jvalue*);
jchar (*CallStaticCharMethod)(JNIEnv*, jclass, jmethodID, ...);
jchar (*CallStaticCharMethodV)(JNIEnv*, jclass, jmethodID, va_list);
jchar (*CallStaticCharMethodA)(JNIEnv*, jclass, jmethodID, jvalue*);
jshort (*CallStaticShortMethod)(JNIEnv*, jclass, jmethodID, ...);
jshort (*CallStaticShortMethodV)(JNIEnv*, jclass, jmethodID, va_list);
jshort (*CallStaticShortMethodA)(JNIEnv*, jclass, jmethodID, jvalue*);
jint (*CallStaticIntMethod)(JNIEnv*, jclass, jmethodID, ...);
jint (*CallStaticIntMethodV)(JNIEnv*, jclass, jmethodID, va_list);
jint (*CallStaticIntMethodA)(JNIEnv*, jclass, jmethodID, jvalue*);
jlong (*CallStaticLongMethod)(JNIEnv*, jclass, jmethodID, ...);
jlong (*CallStaticLongMethodV)(JNIEnv*, jclass, jmethodID, va_list);
jlong (*CallStaticLongMethodA)(JNIEnv*, jclass, jmethodID, jvalue*);
jfloat (*CallStaticFloatMethod)(JNIEnv*, jclass, jmethodID, ...) __NDK_FPABI__;
jfloat (*CallStaticFloatMethodV)(JNIEnv*, jclass, jmethodID, va_list) __NDK_FPABI__;
jfloat (*CallStaticFloatMethodA)(JNIEnv*, jclass, jmethodID, jvalue*) __NDK_FPABI__;
jdouble (*CallStaticDoubleMethod)(JNIEnv*, jclass, jmethodID, ...) __NDK_FPABI__;
jdouble (*CallStaticDoubleMethodV)(JNIEnv*, jclass, jmethodID, va_list) __NDK_FPABI__;
jdouble (*CallStaticDoubleMethodA)(JNIEnv*, jclass, jmethodID, jvalue*) __NDK_FPABI__;
void (*CallStaticVoidMethod)(JNIEnv*, jclass, jmethodID, ...);
void (*CallStaticVoidMethodV)(JNIEnv*, jclass, jmethodID, va_list);
void (*CallStaticVoidMethodA)(JNIEnv*, jclass, jmethodID, jvalue*);
结合上面总结的流程和jni.h中定义的函数,写如下测试代码:
代码功能:调用java层的静态方法,修改静态字段的值,把修改后的字段的值使用TextView显示出来。
void native_staticMethod(JNIEnv * env, jobject obj){
LOGE("native_staticMethod");
//1.获得类中方法id
jclass cls = (*env)->GetObjectClass(env, obj);
jmethodID mid = (*env)->GetStaticMethodID(env,cls,"changeStr","()V");
if (mid == NULL) {
LOGE("GetStaticMethodID error");
return; /* method not found */
}
LOGE("GetStaticMethodID sucess");
//2.调用CallStatic<ReturnValueType>Method函数调用对应函数.
(*env)->CallStaticVoidMethod(env, cls, mid);
}
注册方法的数组:
static JNINativeMethod gMethods[] = {
{"sayHello", "([I)I", (void *)native_sayHello},
{"arrayTry","([Ljava/lang/String;)[Ljava/lang/String;",(void *)native_arrayTry},
{"accessJava","()V",(void *)native_accessJava},
{"accessinstanceJava","()V",(void *)native_accessinstanceJava},
{"staticMethod","()V",(void *)native_staticMethod},
};
添加了staticMethod方法的注册。
java层的调用:
public class MainActivity extends AppCompatActivity {
TextView textView = null;
static String s = "java str";
String ss = "instance str";
static {
System.loadLibrary("hello");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.text);
staticMethod();
textView.setText(s);
}
public native int sayHello(int []arr);
public native String[] arrayTry(String [] arr);
public native void accessJava();
public native void accessinstanceJava();
public native void staticMethod();
public static void changeStr(){
s = "chang str";
}
}
四.访问实例方法
访问实例方法与访问静态方法类似,要注意的主要是:实例方法是属于对象jobject的,而静态方法是属于类的。
4.1普通实例方法
访问普通的实例方法的步骤还是总结为两步:
• 首先通过GetMethodID在给定类中查找方法
如:jmethodID mid = (*env)->GetMethodID(env,cls,”changeStr”,”()V”);
• 通过CallMethod调用
如:(*env)->CallStaticVoidMethod(env, obj, mid);
jni.h中定义的访问实例方法的相关函数有:
jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);
jobject (*CallObjectMethod)(JNIEnv*, jobject, jmethodID, ...);
jobject (*CallObjectMethodV)(JNIEnv*, jobject, jmethodID, va_list);
jobject (*CallObjectMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
jboolean (*CallBooleanMethod)(JNIEnv*, jobject, jmethodID, ...);
jboolean (*CallBooleanMethodV)(JNIEnv*, jobject, jmethodID, va_list);
jboolean (*CallBooleanMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
jbyte (*CallByteMethod)(JNIEnv*, jobject, jmethodID, ...);
jbyte (*CallByteMethodV)(JNIEnv*, jobject, jmethodID, va_list);
jbyte (*CallByteMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
jchar (*CallCharMethod)(JNIEnv*, jobject, jmethodID, ...);
jchar (*CallCharMethodV)(JNIEnv*, jobject, jmethodID, va_list);
jchar (*CallCharMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
jshort (*CallShortMethod)(JNIEnv*, jobject, jmethodID, ...);
jshort (*CallShortMethodV)(JNIEnv*, jobject, jmethodID, va_list);
jshort (*CallShortMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
jint (*CallIntMethod)(JNIEnv*, jobject, jmethodID, ...);
jint (*CallIntMethodV)(JNIEnv*, jobject, jmethodID, va_list);
jint (*CallIntMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
jlong (*CallLongMethod)(JNIEnv*, jobject, jmethodID, ...);
jlong (*CallLongMethodV)(JNIEnv*, jobject, jmethodID, va_list);
jlong (*CallLongMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
jfloat (*CallFloatMethod)(JNIEnv*, jobject, jmethodID, ...) __NDK_FPABI__;
jfloat (*CallFloatMethodV)(JNIEnv*, jobject, jmethodID, va_list) __NDK_FPABI__;
jfloat (*CallFloatMethodA)(JNIEnv*, jobject, jmethodID, jvalue*) __NDK_FPABI__;
jdouble (*CallDoubleMethod)(JNIEnv*, jobject, jmethodID, ...) __NDK_FPABI__;
jdouble (*CallDoubleMethodV)(JNIEnv*, jobject, jmethodID, va_list) __NDK_FPABI__;
jdouble (*CallDoubleMethodA)(JNIEnv*, jobject, jmethodID, jvalue*) __NDK_FPABI__;
void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...);
void (*CallVoidMethodV)(JNIEnv*, jobject, jmethodID, va_list);
void (*CallVoidMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
jobject (*CallNonvirtualObjectMethod)(JNIEnv*, jobject, jclass,jmethodID, ...);
jobject (*CallNonvirtualObjectMethodV)(JNIEnv*, jobject, jclass, jmethodID, va_list);
jobject (*CallNonvirtualObjectMethodA)(JNIEnv*, jobject, jclass, jmethodID, jvalue*);
jboolean (*CallNonvirtualBooleanMethod)(JNIEnv*, jobject, jclass,jmethodID, ...);
jboolean (*CallNonvirtualBooleanMethodV)(JNIEnv*, jobject, jclass,jmethodID, va_list);
jboolean (*CallNonvirtualBooleanMethodA)(JNIEnv*, jobject, jclass, jmethodID, jvalue*);
jbyte (*CallNonvirtualByteMethod)(JNIEnv*, jobject, jclass, jmethodID, ...);
jbyte (*CallNonvirtualByteMethodV)(JNIEnv*, jobject, jclass,jmethodID, va_list);
jbyte (*CallNonvirtualByteMethodA)(JNIEnv*, jobject, jclass,jmethodID, jvalue*);
jchar (*CallNonvirtualCharMethod)(JNIEnv*, jobject, jclass, jmethodID, ...);
jchar (*CallNonvirtualCharMethodV)(JNIEnv*, jobject, jclass, jmethodID, va_list);
jchar (*CallNonvirtualCharMethodA)(JNIEnv*, jobject, jclass,jmethodID, jvalue*);
jshort (*CallNonvirtualShortMethod)(JNIEnv*, jobject, jclass,jmethodID, ...);
jshort (*CallNonvirtualShortMethodV)(JNIEnv*, jobject, jclass,jmethodID, va_list);
jshort (*CallNonvirtualShortMethodA)(JNIEnv*, jobject, jclass, jmethodID, jvalue*);
jint (*CallNonvirtualIntMethod)(JNIEnv*, jobject, jclass, jmethodID, ...);
jint (*CallNonvirtualIntMethodV)(JNIEnv*, jobject, jclass, jmethodID, va_list);
jint (*CallNonvirtualIntMethodA)(JNIEnv*, jobject, jclass, jmethodID, jvalue*);
jlong (*CallNonvirtualLongMethod)(JNIEnv*, jobject, jclass, jmethodID, ...);
jlong (*CallNonvirtualLongMethodV)(JNIEnv*, jobject, jclass, jmethodID, va_list);
jlong (*CallNonvirtualLongMethodA)(JNIEnv*, jobject, jclass, jmethodID, jvalue*);
jfloat (*CallNonvirtualFloatMethod)(JNIEnv*, jobject, jclass, jmethodID, ...) __NDK_FPABI__;
jfloat (*CallNonvirtualFloatMethodV)(JNIEnv*, jobject, jclass, jmethodID, va_list) __NDK_FPABI__;
jfloat (*CallNonvirtualFloatMethodA)(JNIEnv*, jobject, jclass, jmethodID, jvalue*) __NDK_FPABI__;
jdouble (*CallNonvirtualDoubleMethod)(JNIEnv*, jobject, jclass,jmethodID, ...) __NDK_FPABI__;
jdouble (*CallNonvirtualDoubleMethodV)(JNIEnv*, jobject, jclass,jmethodID, va_list) __NDK_FPABI__;
jdouble (*CallNonvirtualDoubleMethodA)(JNIEnv*, jobject, jclass, jmethodID, jvalue*) __NDK_FPABI__;
void (*CallNonvirtualVoidMethod)(JNIEnv*, jobject, jclass, jmethodID, ...);
void (*CallNonvirtualVoidMethodV)(JNIEnv*, jobject, jclass, jmethodID, va_list);
void (*CallNonvirtualVoidMethodA)(JNIEnv*, jobject, jclass,jmethodID, jvalue*);
4.2被子类覆盖的父类方法
我们看到了很多Nonvirtual方法,这是jni提供用来访问被子类赋给的父类的方法的,使用步骤如下:
调用被子类覆盖的父类方法: JNI支持用CallNonvirtualMethod满足这类需求:
• GetMethodID获得method ID
• 调用CallNonvirtualVoidMethod, CallNonvirtualBooleanMethod
上述,等价于如下Java语言的方式:
super.f();
CallNonvirtualVoidMethod可以调用构造函数
4.3构造函数
你可以像调用实例方法一样,调用构造方法,只是此时构造函数的名称叫做””.
综合上面三个知识点,我们设计如下代码时间这些知识:
1.在c函数中调用String类的构造函数新建一个字符串对象。
2.调用java的实例方法,传入我们1中构建的字符串对象,修改TextView的内容。
代码如下:
void native_instanceMethod(JNIEnv * env, jobject obj){
LOGE("native_instanceMethod");
//1.使用String类的构造函数构造String
//1.1找到String类
jclass stringClass = (*env)->FindClass(env, "java/lang/String");
if (stringClass == NULL) {
LOGE("FindClass error");
return;
}
//1.2找到String类的构造函数
jmethodID cid = (*env)->GetMethodID(env, stringClass, "<init>", "([C)V");
if (cid == NULL) {
LOGE("GetMethodID <init> error");
return; /* exception thrown */
}
//1.3创建字符数组
jint len = 10;
jcharArray elemArr = (*env)->NewCharArray(env, len);
if (elemArr == NULL) {
LOGE("NewCharArray error");
return; /* exception thrown */
}
jchar java_char[]={97,98,99,100,101,102,103,104,105,106};//abcdefghij
//1.4设置字符数组
(*env)->SetCharArrayRegion(env, elemArr, 0, len, java_char);
//1.5 创建一个字符串对象
jstring result = (*env)->NewObject(env, stringClass, cid, elemArr);
//2.获得类中方法id
jclass cls = (*env)->GetObjectClass(env, obj);
jmethodID mid = (*env)->GetMethodID(env,cls,"changeTextView","(Ljava/lang/String;)V");
if (mid == NULL) {
LOGE("GetMethodID error");
return; /* method not found */
}
LOGE("GetMethodID sucess");
//2.调用Call<ReturnValueType>Method函数调用对应函数.
(*env)->CallVoidMethod(env, obj, mid,result);
}
注册方法的数组:
static JNINativeMethod gMethods[] = {
{"sayHello", "([I)I", (void *)native_sayHello},
{"arrayTry","([Ljava/lang/String;)[Ljava/lang/String;",(void *)native_arrayTry},
{"accessJava","()V",(void *)native_accessJava},
{"accessinstanceJava","()V",(void *)native_accessinstanceJava},
{"staticMethod","()V",(void *)native_staticMethod},
{"instanceMethod","()V",(void *)native_instanceMethod},
};
java层调用:
static JNINativeMethod gMethods[] = {
{"sayHello", "([I)I", (void *)native_sayHello},
{"arrayTry","([Ljava/lang/String;)[Ljava/lang/String;",(void *)native_arrayTry},
{"accessJava","()V",(void *)native_accessJava},
{"accessinstanceJava","()V",(void *)native_accessinstanceJava},
{"staticMethod","()V",(void *)native_staticMethod},
{"instanceMethod","()V",(void *)native_instanceMethod},
};
访问实例方法的实验到此结束。
五.性能与优化
5.1缓存Field 和 Method IDs
每次获得Field和Method IDS都比较耗时,如果我们需要多次获取他们,那就应该把它们缓存起来,这样以后用的时候就可以直接用了,从而节约了时间。
缓存的方式可以使用局部static字段缓存,也可以在类的初始化时,一次性缓存好全部的Field 和 Method IDs。
上述第一次使用缓存的方式,每次都有与NULL的判断,并且可能有一个无害的竞争条件。
而初始化类时,同时初始化JNI层对该类成员的缓存,可以弥补上述缺憾。
5.2影响jni回调性能的因素
首先比较Java/native和Java/Java
前者因下述原因可能会比后者慢:
• Java/native与Java/Java的调用约定不同. 所以,VM必须在调用前,对参数和调用
栈做特殊准备
• 常用的优化技术是内联. 相比Java/Java调用,Java/native创建内联方法很难
粗略估计:执行一个Java/native调用要比Java/Java调用慢2-3倍. 也可能有一些VM实
现,Java/native调用性能与Java/Java相当。(此种虚拟机,Java/native使用Java/Java
相同的调用约定)。
其次比较native/Java与Java/Java
native/Java调用效率可能与Java/Java有10倍的差距,因为VM一般不会做Callback的
优化。
Android jni/ndk编程三:native访问java的更多相关文章
- Android JNI&NDK编程小结及建议
前言 由于网上关于JNI/NDK相关的知识点介绍的比较零散而且不具备参照性,所以写了这篇JNI/NDK笔记,便于作为随时查阅的工具类型的文章,本文主要的介绍了在平时项目中常用的命令.JNI数据类型.签 ...
- Android jni/ndk编程二:jni数据类型转换(primitive,String,array)
一.数据类型映射概述 从我们开始jni编程起,就不可能避开函数的参数与返回值的问题.java语言的数据类型和c/c++有很多不同的地方,所以我们必须考虑当在java层调用c/c++函数时,怎么正确的把 ...
- Android jni/ndk编程五:jni异常处理
在Java的编程中,我们经常会遇到各种的异常,也会处理各种的异常.处理异常在java中非常简单,我们通常会使用try-catch-finally来处理,也可以使用throw简单抛出一个异常.那么在jn ...
- Android jni/ndk编程四:jni引用类型
一.JNI引用类型 JNI支持三种类型的 opaque reference:local references, global references,和weak global references,下面 ...
- Android之NDK编程(JNI)
转自:http://www.cnblogs.com/xw022/archive/2011/08/18/2144621.html NDK编程入门--C回调JAVA方法 一.主要流程 1. 新建一个 ...
- android Jni NDK开发环境搭建及其简单实例的编写
android Jni NDK开发环境搭建及其简单实例的编写 由于工作需要,需要采用开发想要的JNI,由于之前没有接触过安卓的开发,所以更加网上的帖子,学习了下.遇到了些问题,然后总结下学习过程中 ...
- Android Studio NDK编程初探
继上一篇学习了如何使用NDK编译FFMPEG后,接下来就是要学习如何在Android Studio中使用了. 经过参考和一系列的摸索,记录下具体步骤. 创建C++ Support的Android St ...
- Android Studio JNI/NDK 编程简介(一)
首先说一下概念及相关的东西: JNI : JNI是Java Native Interface的缩写,它提供了若干的API实现了Java和其他语言的通信(主要是C&C++).从Java1.1开始 ...
- 一天掌握Android JNI本地编程 快速入门
一.JNI(Java Native Interface) 1.什么是JNI: JNI(Java Native Interface):java本地开发接口 ...
随机推荐
- 查询表中列转换为json
DECLARE @sql VARCHAR(MAX) SET @sql= (SELECT (select '+'',"'+column_name+'":"''+CAST(' ...
- idea中安装git后,代码颜色代表的含义
idea中安装git以后,代码文件出现了不同的颜色 它们分别表示的含义: 绿色,已经加入控制暂未提交 红色,未加入版本控制 蓝色,加入,已提交,有改动 白色,加入,已提交,无改动 灰色:版本控制已忽略 ...
- Ubuntu 18.04 安装配置 MySQL 5.7
Ubuntu 18.04 安装 mysql 的过程中,竟然没有让你输入秘密?!(之前在 Ubuntu 14.04 下,安装过程中会询问密码),这导致安装完 mysql 初始秘密不知道的问题. $ su ...
- 牛客小白月赛12 H 华华和月月种树 (离线dfs序+线段树)
链接:https://ac.nowcoder.com/acm/contest/392/H 来源:牛客网 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 131072K,其他语言2621 ...
- 第六章 组件 58 组件切换-使用v-if和v-else结合flag进行切换
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8&quo ...
- 下载安装mysql-connector
执行命令:python -m pip install mysql-connector 测试
- JQuery实现简单的服务器轮询效果
很多论坛都有进入后,弹出提示,说有多少封邮件没有看,或者是一个oa系统,进入后,提示有多少个任务没有做.每隔一段时间会提示一次,但是如何实现呢.其实,利用jquery的话,会比较简单,核心元素就是js ...
- axios时遇到的Request Method: OPTIONS
前言 在请求axios 请求数据的时候,会出现options的,是因为请求是分为简单请求和复杂请求. 简单请求 满足下面两个条件的请求是简单请求: 请求方式是以下三种之一: HEAD GET POST ...
- ajax给增删修加入非空
<span>标签加入 <script type="text/javascript"> $(".inp2").click(function ...
- jQuery和vue 设置ajax全局请求
一个很常见的问题,如果用户登录网站session过期,需要用户返回登录页面重新登录. 如果是http请求可以在后台设置拦截器,统一拦截并跳转.但是ajax方法并不能通过后台直接跳转. 所以我们可以写一 ...