美文网首页
Android NDK - JNI 回调Java函数注意事项

Android NDK - JNI 回调Java函数注意事项

作者: chengjian666 | 来源:发表于2018-02-22 14:33 被阅读50次

    被回调的Java静态函数中有数组参数

    假设有如下Java函数待被JNI调用,但是由于Cpp中的数组和java中的数组是属于不同的数据类型,因此是无法直接传递的。
    按照经验,极可能会在JNI中将基本数据类型数组直接传入,但这会报错。
    因此传递之前,一定要C++中的数组进行本地化转换。

    //Java 函数
    package com.test.jni;
    public class TestFunc{
        public static void testFunc(float vals[]){
            //...
        }
    }
    
    //JNI函数回调片段
    jclass clz = jenv->FindClass("com/test/jni/TestFunc");
    jmethodID methodId = env->GetMethodID(clz,"TestFunc","([F)V");
    float[] data = new float[]{1.f,2.f};
    //!!错误示例!!
    env->CallStaticVoidMethod(clz,methodId,data);
    //正确用例
    jfloatArray array = env->NewFloatArray(2);
    //参数1:待赋值数组;参数2:赋值起始位置;参数3:赋值长度;参数4:数据源
    env->SetFloatArrayRegion(array,0,3,data);
    env->CallStaticVoidMethod(clz,methodId,array);
    

    如上例所示,由于C++中的数组与Java中存在差异,所以一定要在本地进行转换之后才能使用。同时,对于基本数据类型(int,float,double等),是可以直接传递的;当然,对待cpp中的string类型,也是不能直接传递的;

    被回调的Java静态函数中有String 参数

    由于CPP和java中的string/String是不同的,无法直接传递,举个栗子:

    //Java 函数
    package com.test.jni;
    public class TestFunc{
        public static void testFunc(String str){
            //...
        }
    }
    
    //JNI函数回调片段
    jclass clz = jenv->FindClass("com/test/jni/TestFunc");
    jmethodID methodId = env->GetMethodID(clz,"TestFunc","(Ljava/lang/String;)V");
    string data = "test";
    //!!错误示例!!
    env->CallStaticVoidMethod(clz,methodId,data);
    //正确用例
    jstring jstring1 = jenv->NewStringUTF(data.c_str());
    env->CallStaticVoidMethod(clz,methodId,jstring1);
    

    对于其他基本数据类型就可以直接传递。

    对于非静态函数调用

    在实际使用场景中,除了静态函数之外,更多的可能还有实例化方法,对于实例化函数的调用,我们势必需要持有一个实例化的引用才可以,所以就涉及本地化实例化操作。
    举个栗子:

    //Java 函数
    package com.test.jni;
    public class TestFunc{
        public TestFunc(){
        }
        
        public void testFunc(String str){
            //...
        }
    }
    
    //JNI函数回调片段
    jclass clz = jenv->FindClass("com/test/jni/TestFunc");
    //获取构造参数,多个构造参数根据函数签名确定
    jmethodID methodIdConstructor = jenv->GetMethodID(clz, "<init>", "()V");
    //通过调用构造函数创建本地化实例
    jobject jobjClz = jenv->NewObject(clz, methodIdConstructor);
    jmethodID methodId = env->GetMethodID(clz,"TestFunc","(Ljava/lang/String;)V");
    //然后便可以调用实例化的方法
    string data = "test";
    jstring jstring1 = jenv->NewStringUTF(data.c_str());
    env->CallVoidMethod(jobjClz,methodId,jstring1);
    

    关于更多的函数签名相关内容,可参考上篇日志。
    CSDN同步发布地址

    相关文章

      网友评论

          本文标题:Android NDK - JNI 回调Java函数注意事项

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