linux jni调用异常,Android JNI开发系列(十三) JNI异常处理

JNI 异常处理

JNI异常与JAVA处理异常的区别

JAVA 有异常处理机制,而JNI没有

如果JAVA中异常没有捕获,后面的代码不会执行,JNI会执行

JAVA编译时的异常,是在方法显示的声明了某一个异常,编译器要求在调用的时候必须显示的捕获

JNI异常举例分析

package org.professor.jni.java;

public class TestException {

public native void testException();

public void exceptionCallback() {

int a = 20 / 0;

System.out.println("--->" + a);

}

}

package org.professor.jni;

import android.support.v7.app.AppCompatActivity;

import android.os.Bundle;

import android.widget.TextView;

import org.professor.jni.java.TestException;

public class MainActivity extends AppCompatActivity {

// Used to load the 'native-lib' library on application startup.

static {

// lib+native-lib+.so

//libnative-lib.so

System.loadLibrary("hello-jni");

}

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

TextView tv = (TextView) findViewById(R.id.sample_text);

// tv.setText(stringFromJNI());

TestException testException = new TestException();

try {

testException.testException();

} catch (Exception e) {

e.printStackTrace();

}

}

}

#include

#include

#ifndef ANDROIDJNIDEMO_TEST_THROW_EXCEPTION_H

#define ANDROIDJNIDEMO_TEST_THROW_EXCEPTION_H

#define LOG_D(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)

#define LOG_I(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)

#define LOG_W(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)

#define LOG_E(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)

#ifdef __cplusplus

extern "C" {

#endif

/*

*

* Class: org_professor_jni_java_TestException

* Method: occorException

* Signature: ()V

*/

JNIEXPORT void JNICALL Java_org_professor_jni_java_TestException_testException

(JNIEnv *, jobject);

#ifdef __cplusplus

}

#endif

#endif //ANDROIDJNIDEMO_TEST_THROW_EXCEPTION_H

//------分割线

#include

#include

#include

#define LOG_TAG "EXCEPTION"

JNIEXPORT void JNICALL

Java_org_professor_jni_java_TestException_testException(JNIEnv *env, jobject instance) {

jclass exception_clazz = (*env)->FindClass(env, "org/professor/jni/java/TestException");

if (NULL == exception_clazz) {

LOG_D("NOT FIND EXCEPTION CLASS");

return;

}

jmethodID test_method_id = (*env)->GetMethodID(env, exception_clazz, "exceptionCallback",

"()V");

if (NULL == test_method_id) {

LOG_E("NOT FIND TEXT METHOD ID");

return;

}

jmethodID default_constructor_method_id = (*env)->GetMethodID(env, exception_clazz, "",

"()V");

if (NULL == default_constructor_method_id) {

LOG_I("NOT FIND DEFAULT CONSTRUCTOR ID ");

return;

}

jobject test_exception_instance = (*env)->NewObject(env, exception_clazz,

default_constructor_method_id);

if (NULL == test_exception_instance) {

LOG_W("NOT FIND TEST EXCEPTION INSTANCE");

return;

}

(*env)->CallVoidMethod(env, test_exception_instance, test_method_id);

LOG_E("In C: CALL exceptionCallback Method!");

// if ((*env)->ExceptionCheck(env)) { // 检查JNI调用是否有引发异常

// (*env)->ExceptionDescribe(env);

(*env)->ExceptionClear(env); // 清除引发的异常,在Java层不会打印异常的堆栈信息

// 如果不清除,后面调用ThrowNew抛出的异常堆栈信息会覆盖前面的异常信息

(*env)->ThrowNew(env, (*env)->FindClass(env, "java/lang/Exception"), "JNI抛出的异常!"); //清除后可以抛出自己的异常 如果不清除,后面调用ThrowNew抛出的异常堆栈信息会覆盖前面的异常信息

// //return;

// }

jthrowable throwable = (*env)->ExceptionOccurred(env);

if (NULL != throwable) {

(*env)->ExceptionDescribe(env);

// (*env)->ExceptionClear(env);

}

LOG_E("In C: CALL exceptionCallback Method! end");

(*env)->DeleteLocalRef(env, exception_clazz);

(*env)->DeleteLocalRef(env, test_exception_instance);

}

分析:

首先在Java代码中,定义一个TestException 类,里面定义了一个native方法,和一个普通方法,在普通方法里面正常会抛出一个异常ArithmeticException

在native代码中调用了exceptionCallback方法,并对其进行异常检查(可以用两种方法对其进行内存检查,代码注释)。

总结

当调用一个JNI函数后,必须先检查、处理、清除异常后再做其它 JNI 函数调用,否则会产生不可预知的结果。

一旦发生异常,立即返回,让调用者处理这个异常。或 调用 ExceptionClear 清除异常,然后执行自己的异常处理代码。

异常处理的相关JNI函数总结:

ExceptionCheck:检查是否发生了异常,若有异常返回JNI_TRUE,否则返回JNI_FALSE

ExceptionOccurred:检查是否发生了异常,若用异常返回该异常的引用,否则返回NULL

ExceptionDescribe:打印异常的堆栈信息

ExceptionClear:清除异常堆栈信息

ThrowNew:在当前线程触发一个异常,并自定义输出异常信息 jint (JNICALL *ThrowNew) (JNIEnv *env, jclass clazz, const char *msg);

Throw:丢弃一个现有的异常对象,在当前线程触发一个新的异常 jint (JNICALL *Throw) (JNIEnv *env, jthrowable obj);

FatalError:致命异常,用于输出一个异常信息,并终止当前VM实例(即退出程序) void (JNICALL *FatalError) (JNIEnv *env, const char *msg);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值