【Tech-Android-Jni】Jni中基本方法(2)

Jni中各种特殊的方法。
1). 加载虚拟机:
函数:jint JNI_CreateJavaVM(JavaVM **pvm, void **penv, void args);
参数说明:JavaVM **pvm JAVA虚拟机指针,第二个参数JNIEnv *env是贯穿整个调用过程的一个参数,因为后面的所有函数都需要这个参数,需注意的是第三个参数,在jdk1.1与1.2版本有些不同,在JDK 1.1中第三个参数总是指向一个结构JDK1_ 1InitArgs,这个结构无法完全在所有版本的虚拟机中进行无缝移植。所以为了保证可移植性,建议使用jdk1.2的方法加载虚拟机。

2). 获取指定对象的类定义:
有两种方法可获得类定义,一是在已知类名的情况使用FindClass来获取;二是通过对象直接得到类定义GetObjectClass.

/* * Class: com_example_jni_ActNative * Method: nativeExec * Signature: (I)I */
JNIEXPORT jint JNICALL Java_com_example_jni_ActNative_nativeExec
  (JNIEnv *env, jclass thiz, jint refer){

    CCounter *co= (CCounter*)refer;
    jobject jo =(jobject)co->javaObj; 
    //获取javaobj的值并存在jo变量中 javaobj存在CounterNative中

    jclass joClazz = (jclass)env->GetObjectClass(jo);//jo的是调用这个方法的(java层)的参考 获取CounterNative
    jmethodID mid =env->GetMethodID(joClazz,"getNumb","()I");//透过jo可以调用_CounterNative对象的getNumb()方法

    int numb = (int)env->CallIntMethod(jo,mid);//透过方法getNumb 获取numb的值
    co->n=numb;//将numb赋值给n;
    return (jint)co->execute();//返回计算的结果

    }

3). 获取要调用的方法:
获得非静态方法:
jmethodID (JNICALL *GetMethodID)(JNIEnv *env, jclass clazz, const char *name, const char *sig);

获得静态方法:
jmethodID (JNICALL *GetStaticMethodID)(JNIEnv *env, jclass class, const char *name, const char *sig);

参数说明:JNIEnv *env初始化是得到的JNI环境;jclass class前面已获取到的类定义;const char *name方法名;const char *sig方法参数定义

详见上代码段中的jmethodID 获取。

4). 调用JAVA类方法:
函数:CallObjectMethod(JNIEnv *env, jobject obj, jmethodID mid);
函数:CallStaticObjectMethod((JNIEnv *env, jobject obj, jmethodID mid);

详见上代码段中的CallIntMethod的方法。

5). 获得类属性的定义:
jfieldID (JNICALL *GetFieldID) (JNIEnv *env, jclass clazz, const char *name, const char *sig);
静态属性:
jfieldID (JNICALL *GetStaticFieldID) (JNIEnv *env, jclass clazz, const char *name, const char *sig);

详细见 jfieldID fid = (jfieldID)env->GetFieldID(clazz,”v”,”I”);//获取调用者的v字段

/* * Class: com_example_jni_CounterNative * Method: nativeSetup * Signature: ()V */
JNIEXPORT void JNICALL Java_com_example_jni_CounterNative_nativeSetup
  (JNIEnv *env, jobject thiz){
    CCounter *obj = new CCounter();//诞生一个CCounter对象
    jclass clazz = (jclass)env->GetObjectClass(thiz);
    jfieldID fid = (jfieldID)env->GetFieldID(clazz,"v","I");//获取调用者的v字段
    env->SetIntField(thiz,fid,(jint)obj);//设置v的值 关联到CCounter指针上 将CCounter的指针对象存在V字段上

    jobject gThiz = (jobject)env->NewGlobalRef(thiz); //获取调用这个方法的类CounterNative的指针 
    obj->javaObj=(jint)gThiz; //将这个类CounterNative的指针存在javaobj上


    };

6). 数组处理:
要创建数组首先要知道类型及长度,JNI提供了一系列的数组类型及操作的函数如:
NewIntArray、NewLongArray、NewShortArray、NewFloatArray、NewDoubleArray、 NewBooleanArray、NewStringUTF、NewCharArray、NewByteArray、NewString,访问通过 GetBooleanArrayElements、GetIntArrayElements等函数。

7). 异常:
由于调用了Java的方法,会产生异常。这些异常在C/C++中无法通过本身的异常处理机制来捕捉到,但可以通过JNI一些函数来获取Java中抛出的异常信息。

8).多线程调用
我们知道JAVA是非常消耗内存的,我们希望在多线程中能共享一个JVM虚拟机,真正消耗大量系统资源的是JAVA虚拟机jvm而不是虚拟机环境 env,jvm是允许多个线程访问的,但是虚拟机环境只能被创建它本身的线程所访问,而且每个线程必须创建自己的虚拟机环境env。JNI提供了两个函 数:AttachCurrentThread和DetachCurrentThread。便于子线程创建自己的虚拟机环境。

你可能感兴趣的:(【Tech-Android-Jni】Jni中基本方法(2))