Android jni/ndk编程三:native访问java

来源:互联网 发布:java new object数组 编辑:程序博客网 时间:2024/05/16 01:38

上一篇博客我们总结了jni中的数据类型的转换,通过实战体验了如何转换基本类型、字符串、以及数组,数组又包括了原始类型数组和对象数组。这一篇博客将继续总结jni基础知识,并通过实际体验掌握jni编程。这篇博客将着重于本地代码访问java代码的相关知识。
本地代码访问java代码,主要是指访问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__;

访问流程:

  1. 获得java层的类:jclass cls = (*env)->GetObjectClass(env, obj);
  2. 获得字段的ID:jfieldID fid = (*env)->GetStaticFieldID(env, cls, “s”, “Ljava/lang/String;”);
  3. 获得字段的值:jstring jstr = (*env)->GetStaticObjectField(env, cls, fid);
  4. 设置字段的值:(*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程序即可看到现象。

二.访问实例字段

有了访问静态字段的经历,在去写访问实例字段的代码就简单多了,这里总结下使用流程:

  1. 获得java层的类:jclass cls = (*env)->GetObjectClass(env, obj);
  2. 获得字段的ID:jfieldID fid = (*env)->GetFieldID(env, cls, “ss”, “Ljava/lang/String;”);
  3. 获得字段的值:jstring jstr = (*env)->GetObjectField(env, obj, fid);
  4. 设置字段的值:(*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的
优化。
最后关于字段访问
对于field的访问,将没什么不同,只是通过JNI访问某对象结构中某个位置的值。

2 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 1岁宝宝咳嗽有痰怎么办 孩子爱动手打家长怎么办 不小心有了孩子该怎么办 2岁多宝宝干咳怎么办 2岁宝宝咳嗽无痰怎么办 打了孩子后悔了怎么办 12小孩脾气很犟怎么办 被学生气着了怎么办 1岁宝宝轻微咳嗽怎么办 4岁宝宝突然呕吐怎么办 4岁儿童突然呕吐怎么办 四岁儿童90身高怎么办 24个月宝宝缺钙怎么办 狗狗总是要人陪着玩怎么办 成年了还是很皮怎么办 三岁儿子太调皮怎么办 10个月宝宝粘人怎么办 6个月宝宝粘人怎么办 9个月宝宝偏矮怎么办 1岁宝宝粘人爱哭怎么办 宝宝2岁半胆小怎么办 5岁宝宝超级粘人怎么办 狗狗吃饭要人喂怎么办 十个月宝宝认人怎么办 一岁宝宝粘人怎么办 9个月宝宝粘妈妈怎么办 一岁的宝宝呕吐怎么办 宝宝一岁八个月太粘人了怎么办 六个月的宝宝好粘人怎么办 两岁半宝宝说话突然结巴了怎么办 1岁宝宝突然呕吐怎么办 宝宝吃坏了呕吐怎么办 1岁宝宝吃饭爱玩怎么办 7岁儿童半夜呕吐怎么办 一个月宝宝粘人怎么办 2岁宝宝太粘人了怎么办 8个月宝宝很粘人怎么办 7个月宝宝呕吐是怎么办 一个月婴儿粘人怎么办 八个月小孩粘人怎么办 一岁的宝宝粘人怎么办