JNI异常处理和缓存策略

Posted developerLinwj

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JNI异常处理和缓存策略相关的知识,希望对你有一定的参考价值。

异常:程序在运行期间没有按照正常的程序逻辑执行,在执行过程当中出现了某种错误,导致程序崩溃。

作用:
1、保证Java代码可以运行
2、补救措施保证C代码继续运行

由于JNI自己抛出的异常,在Java层无法被捕捉,只能在C层清空。而用户通过ThrowNew抛出的异常,可以在Java层捕捉。


public class MyException {
    
    public native void exeception();
    
    private String name = "xiaoming";
    
    public static void main(String[] args) {
        MyException m = new MyException();
        try {
            m.exeception();
        } catch (Throwable e) {
            e.printStackTrace();
        }
        System.out.println("nihao");
    }
    
    //加载动态库
    static {
        System.loadLibrary("ConsoleApplication1");
    }

}


native方法实现

JNIEXPORT void JNICALL Java_com_lwj_test_MyException_exeception
(JNIEnv *env, jobject jobj){
    jclass cls = (*env)->GetObjectClass(env, jobj);
    jfieldID fid = (*env)->GetFieldID(env, cls, "myname", "Ljava/lang/String;");
    //检测是否发生Java异常
    jthrowable exception = (*env)->ExceptionOccurred(env);
    if (exception != NULL){
        //让Java代码可以继续运行
        //清空异常信息
        (*env)->ExceptionClear(env);

        //补救措施
        fid = (*env)->GetFieldID(env, cls, "name", "Ljava/lang/String;");
    }

    //获取属性的值
    jstring jstr = (*env)->GetObjectField(env, jobj, fid);
    char *str = (*env)->GetStringUTFChars(env, jstr, NULL);

    //对比属性值是否合法
    if (_stricmp(str, "xiaoming2") != 0){
        //认为抛出异常,给Java层处理
        jclass newExcCls = (*env)->FindClass(env, "java/lang/IllegalArgumentException");
        (*env)->ThrowNew(env, newExcCls, "key's value is invalid!");
    }
}




关于更加详细的异常处理,大家可以参考这篇文章:《JNI/NDK开发指南(十一)——JNI异常处理》(http://blog.csdn.net/xyang81/article/details/45770551)


缓存策略

1、局部变量使用static jfieldID key_id

Java类:

public class MyException {
    
    public native void cached();
    
    private String name = "xiaoming";
    
    public static void main(String[] args) {
        MyException m = new MyException();
        for(int i = 0;i< 10;i++) {
            m.cached();
        }
    }
    
    //加载动态库
    static {
        System.loadLibrary("ConsoleApplication1");
    }

}


native实现

JNIEXPORT void JNICALL Java_com_lwj_test_MyException_cached
(JNIEnv *env, jobject jobj){
    jclass cls = (*env)->GetObjectClass(env, jobj);
    //获取jfieldID只获取一次
    //局部静态变量
    static jfieldID key_id = NULL;
    if (key_id == NULL){
        key_id = (*env)->GetFieldID(env, cls, "name", "Ljava/lang/String;");
        printf("--------GetFieldID-------\n");
    }
}




从结果中看出只获取一次。


2、全局变量

//初始化全局变量,动态库加载完成之后,立刻缓存起来
jfieldID key_fid;
jmethodID random_mid;
JNIEXPORT void JNICALL Java_com_dongnaoedu_jni_JniTest_initIds(JNIEnv *env, jclass jcls){   
    key_fid = (*env)->GetFieldID(env, jcls, "key", "Ljava/lang/String;");
    random_mid = (*env)->GetMethodID(env, jcls, "genRandomInt", "(I)I");
}


以上是关于JNI异常处理和缓存策略的主要内容,如果未能解决你的问题,请参考以下文章

JNI 异常捕获与处理

JNI/NDK开发指南——JNI异常处理

JNI/NDK开发指南——JNI异常处理

JNI官方中文资料

Android jni/ndk编程五:jni异常处理

异常和TCP通讯