美文网首页Android-NDK/JNIJNI&NDK
JNI&NDK开发最佳实践(七):JNI之本地方法与ja

JNI&NDK开发最佳实践(七):JNI之本地方法与ja

作者: taoyyyy | 来源:发表于2019-07-12 19:09 被阅读6次

    java调用本地方法

    java调用本地方法主要有如下两个场景:

    本地方法调用java

    C/C++访问Java实例方法和静态方法

    // AccessMethod.c
     
    #include "com_study_jnilearn_AccessMethod.h"
     
    /*
     * Class:     com_study_jnilearn_AccessMethod
     * Method:    callJavaStaticMethod
     * Signature: ()V
     */
    JNIEXPORT void JNICALL Java_com_study_jnilearn_AccessMethod_callJavaStaticMethod
    (JNIEnv *env, jclass cls)
    {
        jclass clazz = NULL;
        jstring str_arg = NULL;
        jmethodID mid_static_method;
        // 1、从classpath路径下搜索ClassMethod这个类,并返回该类的Class对象
        clazz =(*env)->FindClass(env,"com/study/jnilearn/ClassMethod");
        if (clazz == NULL) {
            return;
        }
        
        // 2、从clazz类中查找callStaticMethod方法
        mid_static_method = (*env)->GetStaticMethodID(env,clazz,"callStaticMethod","(Ljava/lang/String;I)V");
        if (mid_static_method == NULL) {
            printf("找不到callStaticMethod这个静态方法。");
            return;
        }
        
        // 3、调用clazz类的callStaticMethod静态方法
        str_arg = (*env)->NewStringUTF(env,"我是静态方法");
        (*env)->CallStaticVoidMethod(env,clazz,mid_static_method, str_arg, 100);
        
        // 删除局部引用
        (*env)->DeleteLocalRef(env,clazz);
        (*env)->DeleteLocalRef(env,str_arg);
    }
     
    /*
     * Class:     com_study_jnilearn_AccessMethod
     * Method:    callJavaInstaceMethod
     * Signature: ()V
     */
    JNIEXPORT void JNICALL Java_com_study_jnilearn_AccessMethod_callJavaInstaceMethod
    (JNIEnv *env, jclass cls)
    {
        jclass clazz = NULL;
        jobject jobj = NULL;
        jmethodID mid_construct = NULL;
        jmethodID mid_instance = NULL;
        jstring str_arg = NULL;
        // 1、从classpath路径下搜索ClassMethod这个类,并返回该类的Class对象
        clazz = (*env)->FindClass(env, "com/study/jnilearn/ClassMethod");
        if (clazz == NULL) {
            printf("找不到'com.study.jnilearn.ClassMethod'这个类");
            return;
        }
        
        // 2、获取类的默认构造方法ID
        mid_construct = (*env)->GetMethodID(env,clazz, "<init>","()V");
        if (mid_construct == NULL) {
            printf("找不到默认的构造方法");
            return;
        }
        
        // 3、查找实例方法的ID
        mid_instance = (*env)->GetMethodID(env, clazz, "callInstanceMethod", "(Ljava/lang/String;I)V");
        if (mid_instance == NULL) {
            
            return;
        }
        
        // 4、创建该类的实例
        jobj = (*env)->NewObject(env,clazz,mid_construct);
        if (jobj == NULL) {
            printf("在com.study.jnilearn.ClassMethod类中找不到callInstanceMethod方法");
            return;
        }
        
        // 5、调用对象的实例方法
        str_arg = (*env)->NewStringUTF(env,"我是实例方法");
        (*env)->CallVoidMethod(env,jobj,mid_instance,str_arg,200);
        
        // 删除局部引用
        (*env)->DeleteLocalRef(env,clazz);
        (*env)->DeleteLocalRef(env,jobj);
        (*env)->DeleteLocalRef(env,str_arg);
    }
    

    C/C++访问Java实例变量和静态变量

    // AccessField.c
     
    #include "com_study_jnilearn_AccessField.h"
     
    /*
     * Class:     com_study_jnilearn_AccessField
     * Method:    accessInstanceField
     * Signature: ()V
     */
    JNIEXPORT void JNICALL Java_com_study_jnilearn_AccessField_accessInstanceField
    (JNIEnv *env, jclass cls, jobject obj)
    {
        jclass clazz;
        jfieldID fid;
        jstring j_str;
        jstring j_newStr;
        const char *c_str = NULL;
        
        // 1.获取AccessField类的Class引用
        clazz = (*env)->GetObjectClass(env,obj);
        if (clazz == NULL) {
            return;
        }
        
        // 2. 获取AccessField类实例变量str的属性ID
        fid = (*env)->GetFieldID(env,clazz,"str", "Ljava/lang/String;");
        if (clazz == NULL) {
            return;
        }
        
        // 3. 获取实例变量str的值
        j_str = (jstring)(*env)->GetObjectField(env,obj,fid);
        
        // 4. 将unicode编码的java字符串转换成C风格字符串
        c_str = (*env)->GetStringUTFChars(env,j_str,NULL);
        if (c_str == NULL) {
            return;
        }
        printf("In C--->ClassField.str = %s\n", c_str);
        (*env)->ReleaseStringUTFChars(env, j_str, c_str);
        
        // 5. 修改实例变量str的值
        j_newStr = (*env)->NewStringUTF(env, "This is C String");
        if (j_newStr == NULL) {
            return;
        }
        
        (*env)->SetObjectField(env, obj, fid, j_newStr);
        
        // 6.删除局部引用
        (*env)->DeleteLocalRef(env, clazz);
        (*env)->DeleteLocalRef(env, j_str);
        (*env)->DeleteLocalRef(env, j_newStr);
    }
     
    /*
     * Class:     com_study_jnilearn_AccessField
     * Method:    accessStaticField
     * Signature: ()V
     */
    JNIEXPORT void JNICALL Java_com_study_jnilearn_AccessField_accessStaticField
    (JNIEnv *env, jclass cls)
    {
        jclass clazz;
        jfieldID fid;
        jint num;
        
        //1.获取ClassField类的Class引用
        clazz = (*env)->FindClass(env,"com/study/jnilearn/ClassField");
        if (clazz == NULL) {    // 错误处理
            return;
        }
        
        //2.获取ClassField类静态变量num的属性ID
        fid = (*env)->GetStaticFieldID(env, clazz, "num", "I");
        if (fid == NULL) {
            return;
        }
        
        // 3.获取静态变量num的值
        num = (*env)->GetStaticIntField(env,clazz,fid);
        printf("In C--->ClassField.num = %d\n", num);
        
        // 4.修改静态变量num的值
        (*env)->SetStaticIntField(env, clazz, fid, 80);
        
        // 删除属部引用
        (*env)->DeleteLocalRef(env,clazz);
    }
    

    更多JNI&NDK系列文章,参见:
    JNI&NDK开发最佳实践(一):开篇
    JNI&NDK开发最佳实践(二):CMake实现调用已有C/C++文件中的本地方法
    JNI&NDK开发最佳实践(三):CMake实现调用已有so库中的本地方法
    JNI&NDK开发最佳实践(四):JNI数据类型及与Java数据类型的映射关系
    JNI&NDK开发最佳实践(五):本地方法的静态注册与动态注册
    JNI&NDK开发最佳实践(六):JNI实现本地方法时的数据类型转换
    JNI&NDK开发最佳实践(七):JNI之本地方法与java互调
    JNI&NDK开发最佳实践(八):JNI局部引用、全局引用和弱全局引用
    JNI&NDK开发最佳实践(九):调试篇

    相关文章

      网友评论

        本文标题:JNI&NDK开发最佳实践(七):JNI之本地方法与ja

        本文链接:https://www.haomeiwen.com/subject/tfoykctx.html