如何在JNI中抛异常

前端之家收集整理的这篇文章主要介绍了如何在JNI中抛异常前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
在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);
}

猜你在找的Sqlite相关文章