您当前的位置:首页 > 计算机 > 编程开发 > Java

JNI接口操作实践(二)

时间:08-15来源:作者:点击数:

前面介绍了JNI的基本规范以及JNI的接口的生成过程。本文通过一个jni_test 应用实践操作JNI的接口各种典型应用。

jni_test从jni的字符串,数组,基本类型,自定义类,C回调java静态方法,C回调Java的实例方法,C访问Java的静态变量,C访问Java的实例变量,Java传内存数据给C,C传内存数据给Java 共10个demo演示jni各种典型应用场景。

一、UI设计

通过修改active_main.xml(为了简单起见采用相对布局),或者直接使用design工具拖动布局(先拖一个layout线下布局,再在该布局上排上控件,类似MFC的UI设计原理),UI效果如下。

jni_test的UI界面

二、JIN接口的定义

Java JNI接口声明如下:

public native String stringFromJNI(String src);
public native String CallbackFuncTest();
public native int CallbackClassTest();
public native int CallbackStaticVarTest();
public native int CallbackVarTest(TestNative obj);
public native int add(int x,int y);
public native int [] updateArray(int [] src,int len);
public native void passmem2C(int [] src,int len);
public native int [] getmem2C();

三、在native层jni实现如下:

extern "C" JNIEXPORT jstring JNICALL
Java_com_example_jni_1test_MainActivity_stringFromJNI(
        JNIEnv* env,
        jobject /* this */,
        jstring src) {
    std::string hello = "Hello3 from C++";
    const char* native_string = env->GetStringUTFChars(src, NULL);
    std::string temp(native_string);
    std::string dst = hello+temp;
    env->ReleaseStringUTFChars(src, native_string);
    return env->NewStringUTF(dst.c_str());
}
//回调java 静态的方法
extern "C" JNIEXPORT jstring Java_com_example_jni_1test_MainActivity_CallbackFuncTest(
        JNIEnv* env,
jobject /* this */ ){
    jclass mJclass;
    jstring mJstring;
    jmethodID mJStaticmethodID;
    //1.从classpath路径下搜索ClassMethod这个类,并返回该类的Class对象
    int i = 0;
    mJclass = env->FindClass("com/example/jni_test/TestNative"); //JNIEnv*, const char*
    if (mJclass == NULL) {
        LOGI("test","callJavaStaticMethod==>>mJclass==NULL==>>%s", "");
        return env->NewStringUTF("CallbackTest is failed");
    }
    // 2、从clazz类中查找callStaticMethod方法
    mJStaticmethodID = env->GetStaticMethodID(mJclass,
                                              "settext",
                                              "(Ljava/lang/String;)V"); //JNIEnv*, jclass, const char*, const char*
    if (mJStaticmethodID == NULL) {
        LOGI("test","=====>>>can not foud callStaticMethod");
        return env->NewStringUTF("CallbackFuncTest is failed");
    }
    mJstring= env->NewStringUTF("settext is now");
    env->CallStaticVoidMethod(mJclass, mJStaticmethodID, mJstring);
    // 删除局部引用
    env->DeleteLocalRef(mJstring);
    env->DeleteLocalRef(mJclass);
    return env->NewStringUTF("CallbackFuncTest is now");

}
//回调java中的类
extern "C" JNIEXPORT jint Java_com_example_jni_1test_MainActivity_CallbackClassTest(
        JNIEnv* env,
        jobject /* this */ ) {
    jclass mJclass = NULL;
    jmethodID jmethodID_Construct; //构造方法ID
    jmethodID jmethodID_Method_Instance; //方法的ID
    jmethodID jmethodID_Method_Instance2; //方法的ID
    jobject jobjectMyClass; //类的实例
    //1、从classpath路径下搜索ClassMethod这个类,并返回该类的Class对象
    mJclass = env->FindClass("com/example/jni_test/TestNative");
    if (mJclass == NULL) {
        printf("====FindClass  not found \n");
        return 0;
    }
    // 2、获取类的默认构造方法ID
    jmethodID_Construct = env->GetMethodID(mJclass, "<init>", "(I)V");
    if (jmethodID_Construct == NULL) {
        printf("GetMethodID not found ==>>jmethodID_Construct");
        return 0;
    }
    // 3、查找实例方法的ID
    jmethodID_Method_Instance = env->GetMethodID(mJclass,
                                                 "setnum", "(I)V");
    if (jmethodID_Method_Instance == NULL) {
        return 0;
    }
    // 4、创建该类的实例  调用无参构造方法  如果其它构造方法,后面可传参数
    jobjectMyClass = env->NewObject(mJclass, jmethodID_Construct,100); //JNIEnv*, jclass, jmethodID, ...
    if (jobjectMyClass == NULL) {
        return 0;
    }
    // 5、调用对象的实例方法

    env->CallVoidMethod(jobjectMyClass, jmethodID_Method_Instance,
                        100); //JNIEnv*, jobject, jmethodID, ...
    // 3、查找实例方法的ID
    jmethodID_Method_Instance2 = env->GetMethodID(mJclass,
                                                 "getnum", "()I");
    if (jmethodID_Method_Instance2 == NULL) {
        return 0;
    }
    int ret;
    ret=env->CallIntMethod(jobjectMyClass, jmethodID_Method_Instance2); //JNIEnv*, jobject, jmethodID, ...

    // 删除局部引用
    env->DeleteLocalRef(jobjectMyClass);
    return ret;
}
//回调java中的类中静态变量
extern "C" JNIEXPORT jint Java_com_example_jni_1test_MainActivity_CallbackStaticVarTest(
        JNIEnv* env,
        jobject /* this */ ) {
    jclass clazz;
    jfieldID fid;
   int test;

    //1.获取ClassField类的Class引用
    clazz = env->FindClass("com/example/jni_test/TestNative");
    if (clazz == NULL) { // 错误处理
        return 0;
    }
    //2.获取ClassField类静态变量test的属性ID
    fid = env->GetStaticFieldID(clazz, "iVar", "I");
    if (fid == NULL) {
        return 0;
    }

    // 3.获取静态变量test的值


    test = env->GetStaticIntField(
            clazz,
            fid);
    LOGI("test","test = %d\n", test);
    // 4.修改静态变量num的值
    jint ret = 55;
    env->SetStaticIntField(clazz, fid, ret);
    test = env->GetStaticIntField(
            clazz,
            fid);
    // 删除属部引用
    env->DeleteLocalRef(clazz);
    return test;
}
extern "C" JNIEXPORT int Java_com_example_jni_1test_MainActivity_CallbackVarTest(
        JNIEnv* env,
        jobject /* this */,jobject obj) {
    jclass clazz;
    jfieldID fid;
    jstring j_str;
    jstring j_newStr;
    const char *c_str = NULL;
    // 1.获取AccessField类的Class引用
    clazz = env->GetObjectClass(obj);
    if (clazz == NULL) {
        return 0;
    }
    // 2. 获取AccessField类实例变量str的属性ID
    fid = env->GetFieldID(clazz, "str", "Ljava/lang/String;");
    if (clazz == NULL) {
        return 0;
    }
    // 3. 获取实例变量str的值
    j_str = static_cast<jstring>(env->GetObjectField(obj, fid)); //JNIEnv*, jobject, jfieldID
    if (j_str == NULL) {
        return 0;
    }
    // 4. 将unicode编码的java字符串转换成C风格字符串
    c_str = env->GetStringUTFChars(j_str, NULL); //JNIEnv*, jstring, jboolean*
    if (c_str == NULL) {
        return 0;
    }
    LOGI("test","In C--->ClassField.str = %s\n", c_str);
    env->ReleaseStringUTFChars(j_str, c_str); //JNIEnv*, jstring, const char*
    // 5. 修改实例变量str的值
    j_newStr = env->NewStringUTF("This is new String");
    if (j_newStr == NULL) {
        return 0;
    }
    env->SetObjectField(obj, fid, j_newStr); //JNIEnv*, jobject, jfieldID, jobject

    // 6.删除局部引用
    env->DeleteLocalRef(clazz); //JNIEnv*, jobject
    env->DeleteLocalRef(j_str); //JNIEnv*, jobject
    env->DeleteLocalRef(j_newStr); //JNIEnv*, jobject
    //env->DeleteLocalRef(env,fid);//JNIEnv*, jobject  返回的非object,不能使用 DeleteLocalRef
    //使用NewObject就会返回创建出来的实例的局部引用 可  DeleteLocalRef
    return 1;
}

extern "C" JNIEXPORT jint JNICALL Java_com_example_jni_1test_MainActivity_add
        (JNIEnv *env, jobject, jint x, jint y){
    int x1 =  x;
    int y1 = y;
    int sum = (x1+y1)*200;
    __android_log_print(ANDROID_LOG_DEBUG,"test","hello5 world");
    LOGD("test","hello sum is %d",sum);
    //printf("hello3 world");
   // std::cout<<"hello4 world"<<std::endl;
    return sum;
}
extern "C" JNIEXPORT jintArray JNICALL Java_com_example_jni_1test_MainActivity_updateArray
        (JNIEnv *env, jobject, jintArray src,jint len)
{
    jintArray dst;
    jint *cPArray = env->GetIntArrayElements(src, NULL);
    if (cPArray == NULL) {
        return 0; // JVM复制原始数据到缓冲区失败
    }
  //  jint i;
    for(int i=0;i<len;i++)
    {
        cPArray[i]=cPArray[i]+100;
        LOGD("test","cPArray %d",cPArray[i]);
    }
    //给java层返回数组方式1
    int cInts[len]; //定义一个数组
    for (int i = 0; i < len; i++) {
        cInts[i] = cPArray[i];
    }
    dst = env->NewIntArray(len);
    if (dst == NULL) {
        return NULL; /* out of memory error thrown */
    }
    //move from the temp structure to the java structure  将native数组转换为java层数组
    env->SetIntArrayRegion(dst, 0, sizeof(cInts) / sizeof(cInts[0]),
                           cInts);
    env->ReleaseIntArrayElements(src, cPArray, 0); // 释放可能复制的缓冲区
    return dst;
}
extern "C" JNIEXPORT void JNICALL Java_com_example_jni_1test_MainActivity_passmem2C
        (JNIEnv *env, jobject, jintArray src,jint len) {

    jintArray dst;
    int *cPArray = env->GetIntArrayElements(src, NULL);
    if (cPArray == NULL) {
        return ; // JVM复制原始数据到缓冲区失败
    }
    for(int i=0;i<len;i++)
    {
        *(cPArray+i)=i;
        LOGD("test","cPArray %d",  *(cPArray+i));
    }
    env->ReleaseIntArrayElements(src, cPArray, 0); // 释放可能复制的缓冲区
}
extern "C" JNIEXPORT jintArray JNICALL Java_com_example_jni_1test_MainActivity_getmem2C
        (JNIEnv *env, jobject){
    jintArray dst;
   int *p = (int *)malloc(10);
   if(!p)
   {
       LOGD("test","malloc is failed");
   }
    for(int i=0;i<10;i++)
    {
        *(p+i)=i;
        LOGD("test","navtive cPArray %d",  *(p+i));
    }
    dst = env->NewIntArray(10);
    if (dst == NULL) {
        return NULL; /* out of memory error thrown */
    }
    //move from the temp structure to the java structure  将native数组转换为java层数组
    env->SetIntArrayRegion(dst, 0, 10,p);
    return dst;
}
方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门