Throw Exception through JNI(C++/Java)

项目中遇到android(java)层用到了C++库,C++抛出的异常需要暴露给java link

1. 如何在Jni中Catch Exception

// 该函数负责re-throw异常,稍后定义
void ThrowJNIException(JNIEnv *env, const char *kpFile, int iLine, const string &type, const string &message);
/*Here '__FILE__' and '__LINE__' are predefined macros and part of the C/C++ standard.
  During preprocessing, they are replaced respectively by a constant string
  holding the current file name and by an integer representing the current line number.
  */
#define THROW_JAVA_EXCEPTION(_ENV_, _TYPE_, _INFO_) \
   ThrowJNIException(_ENV_, __FILE__, __LINE__, _TYPE_, _INFO_);

在Jni函数接口中,Catch exception and throw it:

try {
  res = process();
} catch (cv::Exception &e) {  // 比如catch的不同类型的exception
  THROW_JAVA_EXCEPTION(env, string("Opencv ") + typeid(e).name(), e.what());
} catch (std::exception &e) {
  THROW_JAVA_EXCEPTION(env, string("Std ") + typeid(e).name(), e.what());
} catch (...) {
  THROW_JAVA_EXCEPTION(env, "Other", "Other Exception.");
}

2. Jni中定义函数Re-throw Exception

该函数负责re-throw异常

void ThrowJNIException(JNIEnv *env, const char *kpFile, int iLine, const string &type, const string &message) {
  //Creating the error messages
  string error_message = "JNIException!";
  if (kpFile != NULL && !message.empty()) {
    error_message += "\nFile: " + string(kpFile) +
                     "\nLine number: " + boost::lexical_cast<string>(iLine) + //lexical_cast转换函数!!
                     "\nException type: " + type +
                     "\nReason for Exception: " + message + "\n";
  }

  // Find the exception class.
  jclass tClass = env->FindClass("com/my/project/JNIException");  // java端自定义异常,这样可以与java本身的异常区分
  if (env->ExceptionCheck()) {  // 检出是否有此定义
    env->ExceptionDescribe();
    env->ExceptionClear();  // Make sure to clear it, 否则抛到java层就乱了
    LOGE("Not found com/my/project/JNIException, will try to find java/lang/Exception");
    tClass = env->FindClass("java/lang/Exception");  // 也可以find特定类型:IOExpection,OutOfMemoryError...
    if (tClass == NULL) {
      LOGE("Not found java/lang/Exception");
      env->DeleteLocalRef(tClass);
      return;
    }
  }

  //Throw the exception with error info
  env->ThrowNew(tClass, error_message.c_str());
  env->DeleteLocalRef(tClass);
}

3. Android端实现java自定义异常

JNIException.java定义了jni的异常

package com.my.project;

public class JNIException extends Exception {
  public JNIException() {
      super();
  }

  public JNIException(String message) {
      super(message);
  }
}

4. Android端实际调用并catch jni异常

Jni接口:

public native void process(int pram) throws JNIException;

调用该接口并catch异常:

try {
  process();
} catch (JNIException e) {
  Log.e(LOG_TAG, "JNIException: ", e);  // Better than e.printStackTrace(), can be logged into Logger
  finish();
} catch (Exception e) {
  Log.e(LOG_TAG, "Exception: ", e);
  finish();
}
Loading Disqus comments...
Table of Contents