現在取り組んでいるプロジェクトでは、クロスプラットフォームプログラム実装のAndroid部分をコーディングする必要があります。
Android-ndk
を介してコア機能セットが構築され、アプリに含まれています。ネイティブコードで発生する例外/クラッシュは、たまにしか報告されないことがわかりました。エラーが発生すると、次のいずれかの動作が発生します。
NullPointerException
でクラッシュします(通常はネイティブコードの例外ごとに同じ場所にあり、これは大きな苦痛です)。 Javaコードは、Javaコードは問題ありませんが、ネイティブコードエラーは完全にマスクされています。ネイティブコードで発生するエラーに対してコードを「隔離」する方法を見つけることができないようです。 try/catchステートメントは無視されます。私のコードが犯人であるということを除けば、エラーが発生したことをユーザーに警告する機会すらありません。
ネイティブコードがクラッシュする状況に対応する方法について誰かが私を助けてくれますか?
私は同じ問題を抱えていましたが、C++例外をスローすると、Android(ネイティブコードを実行するときに一般的にVM内)これはキャッチされず、VMが死にます(正しく理解できれば、それはあなたの問題だと思います)。私が採用した解決策は、C++で例外をキャッチしてJava例外。次のコードは、私のソリューションの簡単な例です。まず、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);
}
ThrowNewの後、ネイティブメソッドは突然自動的に終了しないことに注意してください。つまり、制御フローはネイティブメソッドに戻り、この時点で新しい例外が保留中です。 JNIメソッドが終了すると、例外がスローされます。
それがあなたが探している解決策だったことを願っています。
EDIT:このよりエレガントな答え も参照してください。
以下のメカニズムは、 [〜#〜] jni [〜#〜] レイヤー内で正常に実装された Cプリプロセッサマクロ に基づいています。
上記のマクロCATCH_CPP_EXCEPTION_AND_THROW_Java_EXCEPTION
は、C++例外をJava例外に変換します。
mypackage::Exception
を独自のC++例外に置き換えます。 Javaで対応するmy.group.mypackage.Exception
を定義していない場合は、"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"); \
}
上記のマクロを使用したファイル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
}
情報や好奇心のために、対応するJavaコード(ファイルexample.Java
)を以下に示します。 "my-DLL-name
"は上記のC/C++コードとしてコンパイルされたものです。 DLL(「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
}
}
まず、example.class
からexample.Java
を生成します(javac
またはお好みの [〜#〜] ide [〜#〜] またはmaven ...を使用します)。次に、javah
を使用してJava_my_group_mypackage_example.h
からC/C++ヘッダーファイルexample.class
を生成します。
この例外をキャッチしてから、ランタイム例外にラップして、スタックの上位に上げることを検討しましたか?
SCJDでも同様の「ハック」を使用しました。一般的に、NPEはあなたの側でエラーを示しますが、何も悪いことをしていないと確信している場合は、例外をバブリングするために例外が使用されることを説明する十分に文書化されたRuntimeException
を作成します。次に、それをアンラップして、たとえばNPEのインスタンスをテストし、独自の例外として処理します。
誤ったデータが発生する場合、他のオプションはありませんが、そのルートに到達します。