博客园2023-03-29 08:03:05
在进行native开发时,还需要注意以下事项:
不要在native方法中直接抛出Java异常。应该使用JNIEnv中提供的函数来创建和抛出Java异常。
(资料图)
不要在native方法中缓存JNIEnv指针,因为它可能会在运行时被释放或重载。
在native方法中访问Java对象时,需要使用JNI提供的函数来获取和操作Java对象,避免直接访问Java对象的内部成员。
注意本地库和Java代码的链接方式和加载顺序,避免出现库加载失败或符号冲突等问题。
在本地库中使用动态内存分配时,需要注意及时释放分配的内存,避免内存泄漏和程序崩溃。
以下是一些常见的native开发注意事项的具体示例:
c++
JNIEXPORT void JNICALLJava_com_example_MyClass_nativeMethod(JNIEnv *env, jobject obj) { jclass exceptionClass = env->FindClass("java/lang/Exception"); env->ThrowNew(exceptionClass, "Native method exception"); // 抛出异常后必须返回,否则代码将继续执行 return;}c++
JNIEXPORT void JNICALLJava_com_example_MyClass_nativeMethod(JNIEnv *env, jobject obj) { jclass cls = env->GetObjectClass(obj); jmethodID methodID = env->GetMethodID(cls, "javaMethod", "()V"); // 缓存JNIEnv指针,容易出现问题 JNIEnv *cachedEnv = env; cachedEnv->CallVoidMethod(obj, methodID); // 应该每次都重新获取JNIEnv指针 env->CallVoidMethod(obj, methodID); return;}c++
JNIEXPORT void JNICALLJava_com_example_MyClass_nativeMethod(JNIEnv *env, jobject obj, jobject jobj) { // 直接访问Java对象的内部成员是不安全的 jclass cls = env->GetObjectClass(jobj); jfieldID fieldID = env->GetFieldID(cls, "field", "Ljava/lang/String;"); jstring str = (jstring)env->GetObjectField(jobj, fieldID); // 应该使用JNI函数来获取和操作Java对象 jclass stringCls = env->FindClass("java/lang/String"); jmethodID lengthID = env->GetMethodID(stringCls, "length", "()I"); int length = env->CallIntMethod(str, lengthID); return;}在Android.mk或CMakeLists.txt中设置链接选项和库依赖,例如:
makefile
LOCAL_LDLIBS := -llog -landroidLOCAL_SHARED_LIBRARIES := libfoo在Java代码中加载本地库,例如:
java
static { System.loadLibrary("mylib");}c++
JNIEXPORT jbyteArray JNICALLJava_com_example_MyClass_nativeMethod(JNIEnv *env, jobject obj, jint size) { jbyte *buffer = new jbyte[size]; // 使用完毕后必须释放内存,避免内存泄漏 jbyteArray result = env->NewByteArray(size); env->SetByteArrayRegion(result, 0, size, buffer); delete[] buffer; return result;} 关键词: