JNI c++对象与java对象互关联

来源:互联网 发布:阿拉丁自有数据电解铝 编辑:程序博客网 时间:2024/06/16 22:06

      android中如果需要调用c++代码需要写jni将java操作转接到c++代码中.但是大部分的文章都只是通过讲解通过  extern "C" 代码来访问具体功能.

     在这里我要讲一种方便的方法将java对象和c++对象互相绑定起来.

     第一步:

    JNIObject.java:

public class JNIObject {    protected long mObj;}
MediaController.java

public class MediaController extends JNIObject {    public MediaController()    {        construct();    }    @Override    protected void finalize() throws Throwable {        destruct();        super.finalize();    }        @Keep    private void logMessage(String msg){        Log.d("AAA", "msg:"+msg);    }    static {        System.loadLibrary("media_controller-lib");    }    private native void construct();    private native void destruct();    public native int ntopen(String file);    public native void ntclose();    public native int ntplay();    public native void ntpause();    public native void ntseek(int sec);    public native String nttest(int msg);}

jni代码:

static JavaVM* g_VM = NULL;class JNIMediaControl        :public MediaControl{public:    JNIMediaControl()    :javaVM(NULL),env_(NULL),thiz(NULL)    {    }    void attachParent(JavaVM * vm,JNIEnv *env,jobject object)    {        javaVM =vm;        thiz = env->NewGlobalRef(object);    }    void detachParent(JNIEnv *env)    {        env->DeleteGlobalRef(thiz);        thiz = NULL;    }private:    void AttachThread()    {        if(javaVM == NULL) return;        if(thiz == NULL) return ;        int ret = javaVM->AttachCurrentThread(&env_,NULL);        if(ret != 0)        {        }    }    void DetachThread()    {        if(javaVM == NULL) return;        javaVM->DetachCurrentThread();        env_ = NULL;    }    virtual void Run()    {        AttachThread();        MediaControl::Run();        DetachThread();    }    void SendPacket(int64_t timestamp,AVFrame *frame)    {        JNIEnv *env = env_;        if(env == NULL) return;        char buffer[64];        sprintf(buffer,"%lld",timestamp);        jstring msg_ = env->NewStringUTF(buffer);        jclass clazz = env->GetObjectClass(thiz);        jmethodID  jid = env->GetMethodID(clazz,"logMessage","(Ljava/lang/String;)V");        env->CallVoidMethod(thiz,jid,msg_);        env->DeleteLocalRef(msg_);    }private:    JavaVM* javaVM;    JNIEnv *env_;    jobject thiz;};
#define  CONSTRUCT(T) { T *t = new T(); \    jclass clazz = (jclass)(*env).GetObjectClass(thiz); \    jfieldID fid = (jfieldID)(*env).GetFieldID(clazz, "mObj", "J"); \    jlong jstr = (jlong) (*env).GetLongField(thiz, fid);  \    (*env).SetLongField(thiz, fid, (jlong)t);}#define OBJECT(T,name) jclass clazz = (jclass)env->GetObjectClass(thiz); \     jfieldID fid = env->GetFieldID(clazz, "mObj","J");  \     T *name = (T *)env->GetLongField(thiz, fid);#define DESTRUCT(T)  {jclass clazz = (jclass)env->GetObjectClass(thiz); \     jfieldID fid = env->GetFieldID(clazz, "mObj","J");  \     T *object = (T *)env->GetLongField(thiz, fid); \     if(object != NULL) delete object; \     (*env).SetLongField(thiz, fid, (jlong)0);}extern "C"JNIEXPORT void JNICALLJava_com_example_jfyang_mediacontrollerdemo_MediaController_construct(JNIEnv* env, jobject thiz){    CONSTRUCT(JNIMediaControl);    OBJECT(JNIMediaControl,control);    if(control == NULL) return ;    control->attachParent(g_VM,env,thiz);}extern "C"JNIEXPORT void JNICALLJava_com_example_jfyang_mediacontrollerdemo_MediaController_destruct(JNIEnv *env,                                                                     jobject thiz) {    {        OBJECT(JNIMediaControl, control);        if (control == NULL) return;        control->detachParent(env);    }    DESTRUCT(JNIMediaControl);}extern "C"JNIEXPORT void JNICALLJava_com_example_jfyang_mediacontrollerdemo_MediaController_ntclose(JNIEnv *env,                                                                      jobject thiz) {    OBJECT(JNIMediaControl,control);    if(control == NULL) return ;    control->Close();}JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved){    JNIEnv* env = NULL;    jint result = -1;    if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {        return -1;    }    assert(env != NULL);    g_VM = vm;    return JNI_VERSION_1_4;}

在android中需要被底层使用的对象均继承自JNIObject.

JNI代码中 通过 

CONSTRUCT构造一个自定义对象与JNIObject关联起来.OBJECT获取与JNIObject关联起来的对象DESTRUCT释放与JNIObject关联起来的对象具体的功能还是通过jni的c方法调用并转至c++对象中.

在jni底层线程中有时需要回调数据至android上层中,这种情况我们可以通过回调上层方法完成.

1.先将上层父对象建立全局引用

thiz = env->NewGlobalRef(object);

注意:所有的在底层线程中操作的上层对象均需要建立GlobalRef才能使用,否则会崩溃.

2.通过JNI_Onload获取本模块加载时传入的虚拟机并全局保存

3.通过虚拟机 在线程中创建一个线程相关JNIEnv.

4.通过线程相关JNIEnv 调用 GlobalRef对象的方法.


原创粉丝点击