如何在JNI中抛异常
发布时间:2020-12-12 20:37:55 所属栏目:百科 来源:网络整理
导读:在android的JNIHelp.h文件中声明四种可以向JVM抛异常的函数: int jniThrowException(JNIEnv* env, const char* className, const char* msg) int jniThrowNullPointerException(JNIEnv* env, char* msg) int jniThrowIOException(JNIEnv* env, int errnum)
在android的JNIHelp.h文件中声明四种可以向JVM抛异常的函数:
intjniThrowException(JNIEnv* env,const char*className,const char*msg)
intjniThrowNullPointerException(JNIEnv* env,char*msg)
intjniThrowIOException(JNIEnv* env,interrnum)
intjniThrowRuntimeException(JNIEnv* env,const char*msg)
注意:虽然
const char*className
它是字符串,但是它是要传到中使用,所以它必须和某个类相对应的。
以上4个函数的定义是JNIHelp.c文件中进行的。查看源码你会发现
jniThrowNullPointerException
、
jniThrowRuntimeException
、
jniThrowIOException
其实就是个特殊的jniThrowException。
其实它们是const char*
className
参数分别为"
java/lang/NullPointerException
"、
"java/lang/RuntimeException
"、"
java/IO/IOException
"的jniThrowException。
它们的使用也很简单,具体可以参照下面的示例代码。
另外注意,这里的抛异常函数并不是在抛异常的同时退出当前函数,而是在函数最终返回时,才真正的抛出异常。
示例1
android_database_SQLiteQuery.cpp文件中的native_fill_window函数
static jint
native_fill_window(JNIEnv* env,jobject object,jobject javaWindow,
jint
startPos,
jint
offsetParam)
{
//略
if (statement == NULL) {
LOGE("Invalid statement in fillWindow()");
jniThrowException(env,"java/lang/IllegalStateException",
"Attempting to access a deactivated,closed,or empty cursor");
return
0;
}
// Only do the binding if there is a valid offsetParam. If no binding needs to be done // offsetParam will be set to 0,an invliad value. if (offsetParam > 0) { // Bind the offset parameter,telling the program which row to start with err = sqlite3_bind_int(statement,offsetParam,startPos); if (err != SQLITE_OK) { LOGE("Unable to bind offset position,offsetParam = %d",offsetParam); jniThrowException(env,"java/lang/IllegalArgumentException", sqlite3_errmsg(GET_HANDLE(env,object))); return 0; } LOG_WINDOW("Bound to startPos %d",startPos); } else { LOG_WINDOW("Not binding to startPos %d",startPos); } // Get the native window window = get_window_from_object(env,javaWindow); if (!window) { LOGE("Invalid CursorWindow"); jniThrowException(env,"Bad CursorWindow"); return 0; } LOG_WINDOW("Window: numRows = %d,size = %d,freeSpace = %d",window->getNumRows(),window->size(),window->freeSpace()); numColumns = sqlite3_column_count(statement); if (!window->setNumColumns(numColumns)) { LOGE("Failed to change column count from %d to %d",window->getNumColumns(),numColumns); jniThrowException(env,"numColumns mismatch"); return 0; } //略 } 示例2 android_util_EventLog.cpp中的android_util_EventLog_readEvents函数 static voidandroid_util_EventLog_readEvents(JNIEnv* env,jobject clazz, jintArray tags, jobject out) { if (tags == NULL || out == NULL) { jniThrowException(env,"java/lang/NullPointerException",NULL); return; } int fd = open("/dev/" LOGGER_LOG_EVENTS,O_RDONLY | O_NONBLOCK); if(fd < 0) { jniThrowIOException(env,errno); return; } jsize tagLength = env->GetArrayLength(tags); jint *tagValues = env->GetIntArrayElements(tags,NULL); uint8_t buf[LOGGER_ENTRY_MAX_LEN]; struct timeval timeout = {0,0}; fd_set readset; FD_ZERO(&readset); for(;;) { // Use a short select() to try to avoid problems hanging on read(). // This means we block for 5ms at the end of the log -- oh well. timeout.tv_usec = 5000; FD_SET(fd,&readset); intr = select(fd + 1,&readset,NULL,&timeout); if (r == 0) { break; // no more events } else if (r < 0 && errno == EINTR) { continue; // interrupted by signal,try again } else if (r < 0) { jniThrowIOException(env,errno); // Will throw on return break; } int len = read(fd,buf,sizeof(buf)); if (len == 0 || (len < 0 && errno == EAGAIN)) { break; // no more events } else if (len < 0 && errno == EINTR) { continue; // interrupted by signal,try again } else if (len < 0) { jniThrowIOException(env,errno); // Will throw on return break; } else if ((size_t) len < sizeof(logger_entry) + sizeof(int32_t)) { jniThrowException(env,"java/io/IOException","Event too short"); break; } //略 } close(fd); env->ReleaseIntArrayElements(tags,tagValues,0); } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |