我的代码从Java开始,调用C ++,然后再为发现,获取和设置字段值之类再次调用Java。
如果有人在寻找C ++方法找到此页面,我将继续研究:
我现在正在做的是用C ++ try / catch块包装JNI方法主体,
JNIEXPORT void JNICALL Java_com_pany_jni_JNIClass_something(JNIEnv* env, jobject self)
{
try
{
... do JNI stuff
// return something; if not void.
}
catch (PendingException e) // (Should be &e perhaps?)
{
/* any necessary clean-up */
}
}
其中PendingException的声明很简单:
class PendingException {};
并且我从C ++调用了任何JNI之后调用了以下方法,因此,如果Java异常状态指示错误,我将立即保释,并让普通的Java异常处理将(Native method)行添加到堆栈跟踪中,同时 让C ++有机会在清理过程中进行清理:
PendingException PENDING_JNI_EXCEPTION;
void throwIfPendingException(JNIEnv* env)
{
if (env->ExceptionCheck()) {
throw PENDING_JNI_EXCEPTION;
}
}
对于失败的env-> GetFieldId()调用,我的Java堆栈跟踪如下所示:
java.lang.NoSuchFieldError: no field with name='opaque' signature='J' in class Lcom/pany/jni/JniClass;
at com.pany.jni.JniClass.construct(Native Method)
at com.pany.jni.JniClass.doThing(JniClass.java:169)
at com.pany.jni.JniClass.access$1(JniClass.java:151)
at com.pany.jni.JniClass$2.onClick(JniClass.java:129)
at android.view.View.performClick(View.java:4084)
与我抛出的Java方法非常相似:
java.lang.RuntimeException: YouSuck
at com.pany.jni.JniClass.fail(JniClass.java:35)
at com.pany.jni.JniClass.getVersion(Native Method)
at com.pany.jni.JniClass.doThing(JniClass.java:172)
我不能谈论将Java异常包装在C ++中的另一个Java异常中,我认为这是您的问题的一部分-我没有发现这样做的必要-但如果这样做,我要么会这样做 围绕本机方法的Java级包装,或者只是扩展我的异常抛出方法以采用jthrowable并用丑陋的东西替换env-> ThrowNew()调用:不幸的是,Sun没有提供使用ThrowNew的版本。 可抛弃。
void impendNewJniException(JNIEnv* env, const char *classNameNotSignature, const char *message)
{
jclass jClass = env->FindClass(classNameNotSignature);
throwIfPendingException(env);
env->ThrowNew(jClass, message);
}
void throwNewJniException(JNIEnv* env, const char* classNameNotSignature, const char* message)
{
impendNewJniException(env, classNameNotSignature, message);
throwIfPendingException(env);
}
我不会考虑缓存(异常)类构造函数引用,因为异常不应被认为是通常的控制流机制,因此,如果它们很慢也没关系。 我想无论如何查找并不会非常慢,因为Java大概会为这种事情做自己的缓存。