项目代码:https://github.com/VincentWei95/ndk
Android JNI开发系列:第一章 JNIEnv接口指针
Android JNI开发系列:第二章 数据类型
Android JNI开发系列:第三章 对引用数据类型的操作
Android JNI开发系列:第四章 异常处理
Android JNI开发系列:第五章 局部和全局引用
Android JNI开发系列:第六章 线程
Android JNI开发系列:第七章 POSIX线程
Android JNI开发系列:第八章 POSIX Socket API 面向连接的通信
Android JNI开发系列:第九章 POSIX Socket API 无连接的通信
Android JNI开发系列:第十章 POSIX Socket API 本地通信
在java中,当抛出一个异常时,虚拟机停止执行代码块并进入调用栈反向检查能处理特定类型异常的异常处理程序代码块,也就是捕获异常。虚拟机清除异常并将控制权交给异常处理程序。
相比之下,JNI要求开发人员在异常发生后显示地实现异常处理流。
1 捕获异常
public class JavaClass {
private void throwingMethod() throws NullPointException
{
throw new NullPointException();
}
private native void accessMethods();
}
jthrowable ex
;
...
(*env
)->CallVoidMethod(env
, instance
, throwingMethodId
);
ex
= (*env
)->ExceptionOccurred(env
);
if (ex
!= 0) {
(*env
)->ExceptionClear(env
);
}
2 抛出异常
因为异常是java类,应该先用FindClass函数找到异常类,再用 ThrowNew 函数初始化抛出异常。
jclazz clazz
;
...
clazz
= (*env
)->FindClass(env
, "java/lang/NullPointerException");
if (clazz
!= 0) {
(*env
)->ThrowNew(env
, clazz
, "Exception message");
}
注意:因为原生函数代码执行不受虚拟机控制,因此抛出异常并不会停止原生函数的执行并把控制权转交给异常处理程序。所以在原生代码抛出异常时,应该释放所有已分配的原生资源。
3 异常demo
com_example_ndk_JNITest.h
#include
<jni.h>
#ifndef _Included_com_example_ndk_JNITest
#define _Included_com_example_ndk_JNITest
#ifdef __cplusplus
extern
"C" {
#endif
JNIEXPORT
void JNICALL Java_com_example_ndk_JNITest_accessExceptionMethod
(JNIEnv
*, jobject
);
JNIEXPORT
void JNICALL Java_com_example_ndk_JNITest_throwExceptionMethod
(JNIEnv
*, jobject
);
#ifdef __cplusplus
}
#endif
#endif
com_example_ndk_JNITest.c
#include
"/include/com_example_ndk_JNITest.h"
#include
<jni.h>
#include
<stdio.h>
#include
<syslog.h>
JNIEXPORT
void JNICALL Java_com_example_ndk_JNITest_accessExceptionMethod
(JNIEnv
*env
, jobject object
) {
jclass clazz
= (*env
)->GetObjectClass(env
, object
);
jmethodID methodId
= (*env
)->GetMethodID(env
, clazz
, "throwingExceptionMethod", "()V");
(*env
)->CallVoidMethod(env
, object
, methodId
);
jthrowable exception
= (*env
)->ExceptionOccurred(env
);
if (exception
!= 0) {
syslog(LOG_ERR
, "native catch exception");
(*env
)->ExceptionClear(env
);
}
}
JNIEXPORT
void JNICALL Java_com_example_ndk_JNITest_throwExceptionMethod
(JNIEnv
*env
, jobject object
) {
jclass exceptionClazz
= (*env
)->FindClass(env
, "java/lang/NullPointerException");
if (exceptionClazz
!= 0) {
(*env
)->ThrowNew(env
, exceptionClazz
, "native throw null pointer exception!");
}
}
JNITest.java
package com
.example
.ndk
;
public class JNITest {
private void throwingExceptionMethod() {
throw new NullPointerException("native access throw null pointer exception!");
}
static {
System
.loadLibrary("ndk");
}
public native void accessExceptionMethod();
public native void throwExceptionMethod();
}
JniActivity.java
package com
.example
.ndk
;
import android
.support
.v7
.app
.AppCompatActivity
;
import android
.os
.Bundle
;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState
) {
super.onCreate(savedInstanceState
);
setContentView(R
.layout
.activity_main
);
JNITest jniTest
= new JNITest();
jniTest
.accessExceptionMethod();
try {
jniTest
.throwExceptionMethod();
} catch (Exception e
) {
e
.printStackTrace();
}
}
}