Android JNI对象与Java对象的绑定

xiaoxiao2021-02-28  114

在Android 开发过程中,经常会用到JNI,要么就是Java调用JNI,要么就是JNI回调Java。一种习惯的做法是把在Java和JNI 都生成相同名字的Class,并将它们互相绑定,这样双方互相调用也非常方便。

例如定义Java class:

public final class NativeTest { private static final String TAG = NativeFfmpeg.class.getSimpleName(); static { System.loadLibrary("test"); NativeTest.nativeClassInit(); } public static native void nativeClassInit(); private native void native_setup(); private native void native_release(); private native void native_test(int value); // bind to Jni class private long mNativeHandle = 0; private void onResult(int result) { Log.e(TAG, "result = " + result); } } JNI 文件如下: #define SAFE_FREE(p) if(p){free(p);p=NULL;} #define DELETE_LOCAL_REF(env, obj) if(obj!=NULL){env->DeleteLocalRef(obj);obj=NULL;} #define DELETE_GLOBAL_REF(env, obj) if(obj!=NULL){env->DeleteGlobalRef(obj);obj=NULL;} #define DELETE_WEAK_GLOBAL_REF(env, obj) if(obj!=NULL){env->DeleteWeakGlobalRef(obj);obj=NULL;} #define JNI_FIELDID(name, field) fieldID_##name_##field #define JNI_METHODID(name, method) methodID_##name_##method #define JNI_DEFINE_FIELDID(name, field) static jfieldID JNI_FIELDID(name, field) = NULL; #define JNI_DEFINE_METHODID(name, method) static jmethodID JNI_METHODID(name, method) = NULL; #define JNI_LOAD_FIELDID(env, clazz, name, field, sig) {JNI_FIELDID(name, field) = (env)->GetFieldID(clazz, #field, sig);__android_log_print(ANDROID_LOG_DEBUG, SV_LOGTAG, "fieldID_"#name"_"#field" = %p", JNI_FIELDID(name, field));} #define JNI_LOAD_METHODID(env, clazz, name, method, sig) {JNI_METHODID(name, method) = (env)->GetMethodID(clazz, #method, sig);__android_log_print(ANDROID_LOG_DEBUG, SV_LOGTAG, "methodID_"#name"_"#method" = %p", JNI_METHODID(name, method));} JNI_DEFINE_FIELDID(NativeTest, mNativeHandle); JNI_DEFINE_METHODID(NativeTest, onResult); class NativeTest { private: jweak mObject; public: NativeTest():mObject(NULL){}; ~NativeTest(){unbind(NULL)}; public: void bind(JNIEnv* env, jobject obj) { jclass clazz = env->GetObjectClass(obj); // refer to Java object mObject = env->NewWeakGlobalRef(obj); DELETE_LOCAL_REF(env, clazz); // bind this Jni object to its Java object(reference) env->SetLongField(mObject, JNI_FIELDID(NativeTest, mNativeHandle), (jlong)this); } void unbind(JNIEnv* env) { if(env == NULL) { jvm->AttachCurrentThread(&env, NULL); } env->SetLongField(mObject, JNI_FIELDID(NativeTest, mNativeHandle), (jlong)0); DELETE_WEAK_GLOBAL_REF(env, mObject); } void test(JNIEnv* env, int value) { if(env == NULL) { jvm->AttachCurrentThread(&env, NULL); } if(mObject != NULL && JNI_METHODID(NativeTest, onResult) != NULL) { env->CallVoidMethod(mObject, JNI_METHODID(NativeTest, onResult), ++value); } } } static void nativeClassInit(JNIEnv* env, jclass clazz) { jclass clazz = env->FindClass(kNativeTestPath); JNI_LOAD_FIELDID(env, clazz, NativeTest, mNativeHandle, "J"); JNI_LOAD_METHODID(env, clazz, NativeTest, onResult, "(I)V"); DELETE_LOCAL_REF(env, clazz); } static void native_setup(JNIEnv* env, jobject thiz) { NativeTest* nt = new NativeTest(); nt->bind(env, thiz); } static void native_release(JNIEnv* env, jobject thiz) { jlong handle = env->GetLongField(thiz, JNI_FIELDID(NativeTest, mNativeHandle)); NativeTest* nt = (NativeTest*)handle; if(nt != NULL) { nt->unbind(env); delete nt; } } static void native_test(JNIEnv* env, jobject thiz, jint value) { jlong handle = env->GetLongField(thiz, JNI_FIELDID(NativeTest, mNativeHandle)); NativeTest* nt = (NativeTest*)handle; if(nt != NULL) { nt->test(env, value); } } static JNINativeMethod gNativeFfmpegMethod[] = { {"nativeClassInit", "()V", (void*)nativeClassInit }, {"native_setup", "()V", (void*)native_setup }, {"native_release", "()V", (void*)native_release }, {"native_test", "(I)V", (void*)native_test }, }

转载请注明原文地址: https://www.6miu.com/read-67261.html

最新回复(0)