zoukankan      html  css  js  c++  java
  • (三)JNI常用示例

    针对我之前文章的练习:JNI方法总结

    1. 字符串

    JAVA层:

    test.testString("HELLOWORLD");

    JNI层:

    JNIEXPORT jstring JNICALL Java_com_aplex_canopen_CANopen_testString(JNIEnv *env, jobject obj, jstring str){
    
        jboolean isCopy;
        const char *cstr = env->GetStringUTFChars(str, &isCopy);  //这个是把android默认的Unicode编码转换为UTF-8编码,然后得到数据
    
        if(isCopy==JNI_FALSE){
            LOGD("错误");
        } else if(isCopy==JNI_TRUE){
            LOGD("正确");
        }
        LOGD("UTF-8数据为:%s", cstr);
        LOGD("UTF-8数据长度为:%d", env->GetStringUTFLength(str));
        LOGD("Unicode数据长度为:%d", env->GetStringLength(str));
    
        env->ReleaseStringUTFChars(str, cstr);
    
        std::string strin = "hello world";
        return env->NewStringUTF(strin.c_str());  //生成一个新的UTF-8格式字符串
    }

    结果:

     D/Canopencommand: 正确
     D/Canopencommand: UTF-8数据为:HELLOWORLD
     D/Canopencommand: UTF-8数据长度为:10
     D/Canopencommand: Unicode数据长度为:10

    2. 基本类型数组

    java层:

    test.testArray(new int[]{1,2,3,4,5,6,7,8,9});

    JNI层:

    JNIEXPORT void JNICALL Java_com_aplex_canopen_CANopen_testArray
            (JNIEnv *env, jobject obj, jintArray arr){
        jboolean isCopy;
        LOGD("######基本类型数组测试#########");
    
        //1. 拿到数组长度
        jint len = env->GetArrayLength(arr);
        LOGD("数组长度为:%d",len);
    
        //2. 拿到数组方法一:也就是转成可用的int*
        jint* val = env->GetIntArrayElements(arr, &isCopy);
        if(isCopy){
            LOGD("数组元素为");
            for (int i = 0; i < len; ++i) {
                LOGD("元素%d:%d",i,val[i]);
            }
        }
    
        //3. 拿到数组方法二:拿指定长度数组
        jint val1[len];
        env->GetIntArrayRegion(arr, 0, len, val1);  //0:起始索引; len: 长度; buf:需要放入的地方
        LOGD("数组元素1为");
        for (int i = 0; i < len; ++i) {
            LOGD("元素%d:%d",i,val1[i]);
        }
    }

    结果

    D/Canopencommand: ######基本类型数组测试#########
    D/Canopencommand: 数组长度为:9
    D/Canopencommand: 数组元素为
    D/Canopencommand: 元素0:1
    D/Canopencommand: 元素1:2
    D/Canopencommand: 元素2:3
    D/Canopencommand: 元素3:4
    D/Canopencommand: 元素4:5
    D/Canopencommand: 元素5:6
    D/Canopencommand: 元素6:7
    D/Canopencommand: 元素7:8
    D/Canopencommand: 元素8:9
    D/Canopencommand: 数组元素1为
    D/Canopencommand: 元素0:1
    D/Canopencommand: 元素1:2
    D/Canopencommand: 元素2:3
    D/Canopencommand: 元素3:4
    D/Canopencommand: 元素4:5
    D/Canopencommand: 元素5:6
    D/Canopencommand: 元素6:7
    D/Canopencommand: 元素7:8
    D/Canopencommand: 元素8:9

    3. 对象类型数组

    JAVA层:

    test.testArrayObject(new String[]{"haha","hehe","wawa","dada"});

    JNI层:

    JNIEXPORT void JNICALL Java_com_aplex_canopen_CANopen_testArrayObject
            (JNIEnv *env, jobject obj, jobjectArray strArr){
        jboolean isCopy;
        LOGD("######对象类型数组测试#########");
    
        int len = env->GetArrayLength(strArr);  //拿到数组长度
    
        //1. 拿到对象数组数据
        for (int i = 0; i < len; ++i) {
            jstring str = (jstring)env->GetObjectArrayElement(strArr, i);  //拿到对象数组的元素:注意要强制转换
            const char *cstr = env->GetStringUTFChars(str, &isCopy);
            LOGD("字符串%d为:%s",i,cstr);
            env->ReleaseStringUTFChars(str, cstr);
        }
    
        //2. 设置对象数组数据
        jstring str = env->NewStringUTF("abcdefg");
        env->SetObjectArrayElement(strArr, 0, str);    //修改对象数组中的数据
        LOGD("修改后再看一遍2");
        for (int i = 0; i < len; ++i) {
            jstring str = (jstring)env->GetObjectArrayElement(strArr, i);
            const char *cstr = env->GetStringUTFChars(str, &isCopy);
            LOGD("字符串%d为:%s",i,cstr);
            env->ReleaseStringUTFChars(str, cstr);
        }
    
        //3. 构造一个新的对象数组
        jclass strClass = env->FindClass("java/lang/String");
        jobjectArray newStr = env->NewObjectArray(len-1, strClass, 0);    //创建一个新的对象数组
        len = env->GetArrayLength(newStr);     //拿到新创立数组的长度
        for (int i = 0; i < len; ++i) {
            jstring str = (jstring)env->GetObjectArrayElement(strArr, i);  //拿到对象数组的元素:注意要强制转换
            env->SetObjectArrayElement(newStr, i, str);    //修改对象数组中的数据
        }
        LOGD("修改后再看一遍3");
        for (int i = 0; i < len; ++i) {
            jstring str = (jstring)env->GetObjectArrayElement(newStr, i);
            const char *cstr = env->GetStringUTFChars(str, &isCopy);
            LOGD("字符串%d为:%s",i,cstr);
            env->ReleaseStringUTFChars(str, cstr);
        }
    
    }

    结果:

    ######对象类型数组测试#########
    D/Canopencommand: 字符串0为:haha
    D/Canopencommand: 字符串1为:hehe
    D/Canopencommand: 字符串2为:wawa
    D/Canopencommand: 字符串3为:dada
    D/Canopencommand: 修改后再看一遍2
    D/Canopencommand: 字符串0为:abcdefg
    D/Canopencommand: 字符串1为:hehe
    D/Canopencommand: 字符串2为:wawa
    D/Canopencommand: 字符串3为:dada
    D/Canopencommand: 修改后再看一遍3
    D/Canopencommand: 字符串0为:abcdefg
    D/Canopencommand: 字符串1为:hehe
    D/Canopencommand: 字符串2为:wawa

    4. 在JNI中调用实例化对象中的方法1:(使用自身对象,自身已被实例化)

    JAVA层:测试对象

    public class CANopen {
        private static final String TAG = "CANopen";
    
        static {
            Log.d(TAG, "static1");
            System.loadLibrary("Canopen-lib");
            Log.d(TAG, "static2");
        }
    
        public native void testCallMethod();
    
    
        private void JNIcallback(){
            Log.d(TAG, "这是JNI从C/C++回调JAVA实例化对象中的方法");
        }
    
        private int JNIcallback2(int a, byte b){
            Log.d(TAG, "整型="+a+";字节="+b);
            return 3;
        }
    
        private String JNIcallback3(int a, String b, byte[]c){
            Log.d(TAG, "整型="+a);
            Log.d(TAG,"字符串="+b);
            Log.d(TAG,"数组长度="+c.length);
            return new String("hello world");
        }
    }

    JAVA层:

    Log.d(TAG, "onCreate1");
    caNopen.testCallMethod();
    Log.d(TAG, "onCreate2");

    JNI层:

    JNIEXPORT void JNICALL Java_com_aplex_canopen_CANopen_testCallMethod
            (JNIEnv *env, jobject obj){
        jboolean isCopy;
    
        //1. 先调用一个比较简单的(无参无返回)
        LOGD("##########第一个############");
        jclass jc = env->GetObjectClass(obj);       //通过实例化对象找到类
        jmethodID id = env->GetMethodID(jc, "JNIcallback", "()V");  //找到实例化对象里函数的ID
        env->CallVoidMethod(obj, id);    //调用obj这个实例化对象里的函数id
    
        //2. 调用稍微复杂点的(基本类型参数和返回值)
        LOGD("##########第二个############");
        jclass jc2 = env->GetObjectClass(obj);       //通过实例化对象找到类
        jmethodID id2 = env->GetMethodID(jc2, "JNIcallback2", "(IB)I");  //找到实例化对象里函数的ID
        jint i = env->CallIntMethod(obj, id2, 0x1234, 5);    //调用obj这个实例化对象里的函数id
        LOGD("JNI中返回参数=%d",i);
    
        //3. 调用一个比较复杂的(带对象类型参数和返回值)
        LOGD("##########第三个############");
        jclass jc3 = env->GetObjectClass(obj);       //通过实例化对象找到类
        jmethodID id3 = env->GetMethodID(jc3, "JNIcallback3", "(ILjava/lang/String;[B)Ljava/lang/String;");  //找到实例化对象里函数的ID
        //创建byte数组,注意:无法赋值!!!
        jbyteArray byteArray = env->NewByteArray(45);
        int len = env->GetArrayLength(byteArray);
        //创建一个string并赋值
        jstring jstr = env->NewStringUTF("fuck!!");
        jstring str = (jstring)env->CallObjectMethod(obj, id3, 12, jstr,byteArray);  //调用obj2这个实例化对象里的函数id,返回值是对象,要进行强制转换
        const char* cstr = env->GetStringUTFChars(str,&isCopy);
        LOGD("JNI中打印:%s", cstr);
        env->ReleaseStringUTFChars(str, cstr);
    
    }

    结果:

     D/MainActivity: onCreate1
     D/Canopencommand: ##########第一个############
     D/CANopen: 这是JNI从C/C++回调JAVA实例化对象中的方法
     D/Canopencommand: ##########第二个############
     D/CANopen: 整型=4660;字节=5
     D/Canopencommand: JNI中返回参数=3
     D/Canopencommand: ##########第三个############
     D/CANopen: 整型=12
     D/CANopen: 字符串=fuck!!
     D/CANopen: 数组长度=45
     D/Canopencommand: JNI中打印:hello world
     D/MainActivity: onCreate2

    5. 在JNI中调用实例化对象中的方法2:(新建实例化对象,修改对象的属性值,调用对象方法)

     需要实例化的对象:

    package com.aplex.canopen;
    
    import android.util.Log;
    
    
    public class TestClass {
        private String TAG = "TestClass";
        private int a;
        TestClass(){
            a = 1;
            Log.d(TAG,"调用无参构造函数");
        }
    
        TestClass(int a){
            this.a = a;
            Log.d(TAG,"调用有参构造函数="+a);
        }
    
        public int getValue(){
            Log.d(TAG, "a="+this.a);
            return this.a;
        }
    }

    JAVA层:

    Log.d(TAG, "onCreate1");
    caNopen.testCallMethod2();
    Log.d(TAG, "onCreate2");

    JNI层:

    JNIEXPORT void JNICALL Java_com_aplex_canopen_CANopen_testCallMethod2
            (JNIEnv *env, jobject obj){
        //1. 调用无参构造函数、修改变量(属性)值
        LOGD("##########调用无参构造函数############");
        jclass jc = env->FindClass("com/aplex/canopen/TestClass");  //找到类,该类未被实例化
        jmethodID initID = env->GetMethodID(jc, "<init>", "()V");//找到构造函数的id;注意:构造函数"<init>"为固定值
        jobject mobj = env->NewObject(jc, initID);  //实例化一个对象
    
        jmethodID funcID = env->GetMethodID(jc, "getValue", "()I");  //拿到方法的ID
        jint i = env->CallIntMethod(mobj, funcID);               //调用方法
        LOGD("修改前查看函数返回的a=%d",i);
        jfieldID fieldID = env->GetFieldID(jc, "a", "I");   //拿到变量(属性)的ID
        jint ii = env->GetIntField(mobj, fieldID);
        LOGD("查看拿到的值a=%d",ii);
        ii = 100;
        env->SetIntField(mobj, fieldID, ii);
        jint iii = env->CallIntMethod(mobj, funcID);               //再次调用查看是否修改属性值
        LOGD("修改后查看函数返回的a=%d",iii);
    
        //2. 调用有参构造函数
        LOGD("##########调用有参构造函数############");
        jclass jc2 = env->FindClass("com/aplex/canopen/TestClass");
        jmethodID initID2 = env->GetMethodID(jc2, "<init>", "(I)V");   //注意这里:"(I)V"
        jobject mobj2 = env->NewObject(jc2, initID2, 123);
        jmethodID funcID2 = env->GetMethodID(jc2, "getValue", "()I");
        jint i2 = env->CallIntMethod(mobj2, funcID2);
        LOGD("a=%d",i2);
    }

    结果:

     D/MainActivity: onCreate1
     D/Canopencommand: ##########调用无参构造函数############
     D/TestClass: 调用无参构造函数
     D/TestClass: a=1
     D/Canopencommand: 修改前查看函数返回的a=1
     D/Canopencommand: 查看拿到的值a=1
     D/TestClass: a=100
     D/Canopencommand: 修改后查看函数返回的a=100
     D/Canopencommand: ##########调用有参构造函数############
     D/TestClass: 调用有参构造函数=123
     D/TestClass: a=123
     D/Canopencommand: a=123
     D/MainActivity: onCreate2

    6. 异常处理

    JAVA层:

    caNopen.testException();

    JNI层:

    JNIEXPORT void JNICALL Java_com_aplex_canopen_CANopen_testException
            (JNIEnv *env, jobject obj){
        jclass jc = env->FindClass("java/io/IOException");
        env->ThrowNew(jc, "异常测试");
    
    }

    结果:

     E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.aplex.canopen, PID: 20296
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.aplex.canopen/com.aplex.canopen.MainActivity}: java.io.IOException: 异常测试
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2416)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476)
    at android.app.ActivityThread.-wrap11(ActivityThread.java)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    at android.os.Looper.loop(Looper.java:148)
    at android.app.ActivityThread.main(ActivityThread.java:5422)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
    Caused by: java.io.IOException: 异常测试
    at com.aplex.canopen.CANopen.testException(Native Method)
    at com.aplex.canopen.MainActivity.onCreate(MainActivity.java:46)
    at android.app.Activity.performCreate(Activity.java:6251)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1107)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2369)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476) 
    at android.app.ActivityThread.-wrap11(ActivityThread.java) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344) 
    at android.os.Handler.dispatchMessage(Handler.java:102) 
    at android.os.Looper.loop(Looper.java:148) 
    at android.app.ActivityThread.main(ActivityThread.java:5422) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616
  • 相关阅读:
    Linux/UNIX套接字连接
    javascript 数组去重
    android开发步步为营之68:Facebook原生广告接入总结
    Java虚拟机内存区域堆(heap)的管理
    honeywell D6110开发的一个工厂仓库追溯识别
    [Asp.net MVC]Asp.net MVC5系列——添加模型
    [Asp.net MVC]Asp.net MVC5系列——添加视图
    [Asp.net MVC]Asp.net MVC5系列——第一个项目
    [SQL]死锁处理语句
    [EF]使用EF简单增删改查
  • 原文地址:https://www.cnblogs.com/maogefff/p/8386768.html
Copyright © 2011-2022 走看看