Android JNI对象与Java对象的绑定

在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 },
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值