Gra*_*eme 51 java-native-interface android exception-handling nullpointerexception android-ndk
我正在进行的项目要求我编写跨平台程序实现的android部分.
构建了一组核心功能,并将其包含在我的应用程序中android-ndk
.我发现在本机代码中发生的任何异常/崩溃只会在现在和最后再次报告.发生错误时,我会收到以下行为之一:
NullPointerException
(通常在每个本机代码异常的相同位置,这是一个巨大的痛苦).通常会让我花费一段时间来尝试调试为什么Java代码抛出错误只是为了发现Java代码很好并且本机代码错误已被完全掩盖.我似乎无法找到任何方法来"隔离"我的代码以防止在本机代码中发生的错误.Try/catch语句被彻底忽略了.除了我的代码被指责为罪魁祸首之外,我甚至没有机会警告用户而不是发生错误.
有人可以帮我解决如何应对崩溃本机代码的情况吗?
jav*_*anz 50
我曾经遇到同样的问题,确实在android(在执行本机代码时通常在任何VM中)如果你抛出一个C++异常并且没有捕获到这个,VM死了(如果我理解正确,我认为它是你的问题).我采用的解决方案是捕获C++中的任何异常并抛出java异常而不是使用JNI.下一个代码是我解决方案的简化示例.首先,您有一个捕获C++异常的JNI方法,然后在try子句中注释Java异常.
JNIEXPORT void JNICALL Java_com_MyClass_foo (JNIEnv *env, jobject o,jstring param)
{
try
{
// Your Stuff
...
}
// You can catch std::exception for more generic error handling
catch (MyCxxException e)
{
throwJavaException (env, e.what());
}
}
void throwJavaException(JNIEnv *env, const char *msg)
{
// You can put your own exception here
jclass c = env->FindClass("company/com/YourException");
if (NULL == c)
{
//B plan: null pointer ...
c = env->FindClass("java/lang/NullPointerException");
}
env->ThrowNew(c, msg);
}
Run Code Online (Sandbox Code Playgroud)
请注意,在ThrowNew之后,本机方法不会突然自动终止.也就是说,控制流返回到您的本机方法,此时新的异常处于挂起状态.JNI方法完成后将抛出异常.
我希望这是你正在寻找的解决方案.
编辑: 另见这个更优雅的答案.
上面的宏CATCH_CPP_EXCEPTION_AND_THROW_JAVA_EXCEPTION
将C++异常转换为Java异常.
替换mypackage::Exception
为您自己的C++异常.如果您没有my.group.mypackage.Exception
在Java中定义相应的,则替换"my/group/mypackage/Exception"
为"java/lang/RuntimeException"
.
#define CATCH_CPP_EXCEPTION_AND_THROW_JAVA_EXCEPTION \
\
catch (const mypackage::Exception& e) \
{ \
jclass jc = env->FindClass("my/group/mypackage/Exception"); \
if(jc) env->ThrowNew (jc, e.what()); \
/* if null => NoClassDefFoundError already thrown */ \
} \
catch (const std::bad_alloc& e) \
{ \
/* OOM exception */ \
jclass jc = env->FindClass("java/lang/OutOfMemoryError"); \
if(jc) env->ThrowNew (jc, e.what()); \
} \
catch (const std::ios_base::failure& e) \
{ \
/* IO exception */ \
jclass jc = env->FindClass("java/io/IOException"); \
if(jc) env->ThrowNew (jc, e.what()); \
} \
catch (const std::exception& e) \
{ \
/* unknown exception */ \
jclass jc = env->FindClass("java/lang/Error"); \
if(jc) env->ThrowNew (jc, e.what()); \
} \
catch (...) \
{ \
/* Oops I missed identifying this exception! */ \
jclass jc = env->FindClass("java/lang/Error"); \
if(jc) env->ThrowNew (jc, "unidentified exception"); \
}
Run Code Online (Sandbox Code Playgroud)
Java_my_group_mypackage_example.cpp
使用上面的宏的文件:
JNIEXPORT jlong JNICALL Java_my_group_mypackage_example_function1
(JNIEnv *env, jobject object, jlong value)
{
try
{
/* ... my processing ... */
return jlong(result);
}
CATCH_CPP_EXCEPTION_AND_THROW_JAVA_EXCEPTION
return 0;
}
JNIEXPORT jstring JNICALL Java_my_group_mypackage_example_function2
(JNIEnv *env, jobject object, jlong value)
{
try
{
/* ... my processing ... */
jstring jstr = env->NewStringUTF("my result");
return jstr;
}
CATCH_CPP_EXCEPTION_AND_THROW_JAVA_EXCEPTION
return 0;
}
JNIEXPORT void JNICALL Java_my_group_mypackage_example_function3
(JNIEnv *env, jobject object, jlong value)
{
try
{
/* ... my processing ... */
}
CATCH_CPP_EXCEPTION_AND_THROW_JAVA_EXCEPTION
}
Run Code Online (Sandbox Code Playgroud)
仅供参考或好奇,我在下面提供相应的Java代码(文件example.java
).注意" my-DLL-name
"是上面编译为DLL的C/C++代码(" my-DLL-name
"没有" .dll
"扩展名).这也适用于Linux/Unix共享库*.so
.
package my.group.mypackage;
public class Example {
static {
System.loadLibrary("my-DLL-name");
}
public Example() {
/* ... */
}
private native int function1(int); //declare DLL functions
private native String function2(int); //using the keyword
private native void function3(int); //'native'
public void dosomething(int value) {
int result = function1(value);
String str = function2(value); //call your DLL functions
function3(value); //as any other java function
}
}
Run Code Online (Sandbox Code Playgroud)
首先,example.class
从example.java
(使用javac
或您最喜欢的IDE或maven ...)生成.其次,生成C/C++头文件Java_my_group_mypackage_example.h
从example.class
使用javah
.