EasyDarwin安卓直播之EasyPusher NDK开发:JNI回调函数的实现

来源:互联网 发布:linux下软件安装 编辑:程序博客网 时间:2024/06/06 07:11

最近在做EasyDarwin的EasyPusher手机直播项目开发时涉及到JNI回调,今日便研究了一下,跟native调用Java层的代码不同,此文说的是直接通过setCallback的方式去实现回调:

先看一下加载so库的代码,我就直接在Activity中使用了:

package org.easydarwin.hellojni;import android.app.Activity;import android.util.Log;import android.os.Bundle;public class HelloJni extends Activity {    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setValueSetCallback(new OnValueSetCallback() {            @Override            public void onValueSet(String value) {                Log.i("callback__", "callback__" + value);            }        });        setValue("1234");        setValue("12345");        setValue("123456");    }    /**     * 回调接口     */    public interface OnValueSetCallback {        void onValueSet(String value);    }    /**     * 设置回调函数     */    public native void setValueSetCallback(OnValueSetCallback callback);    public native void setValue(String value);    static {        System.loadLibrary("hello-jni");    }}

上面的文件是直接在ndk的hello-jni demo的基础上修改的。OnValueSetCallback就是事件的回调接口,通过setValueSetCallback设置回调函数,onValueSet为具体回调处理方法,这里测试的时候是将通过setValue方法set的value在callback中打印出来,来证明回调事件调用成功了。

下面看具体的native层代码:

#include <pthread.h>#include <jni.h>#include <stdio.h>#define _JNI_VERSION JNI_VERSION_1_4#define THREAD_NAME "lib_hello_jni"JNIEnv *jni_get_env(const char *name);/* * Pointer to the Java virtual machine * Note: It's okay to use a static variable for the VM pointer since there * can only be one instance of this shared library in a single VM */static JavaVM *myVm;static pthread_key_t jni_env_key;static jobject callback_obj = NULL;/* * This function is called when a thread attached to the Java VM is canceled or * exited */static void jni_detach_thread(void *data) {    (*myVm)->DetachCurrentThread(myVm);}JNIEnv *jni_get_env(const char *name) {    JNIEnv *env;    env = pthread_getspecific(jni_env_key);    if (env == NULL) {        if ((*myVm)->GetEnv(myVm, (void **) &env, _JNI_VERSION) != JNI_OK) {            /* attach the thread to the Java VM */            JavaVMAttachArgs args;            jint result;            args.version = _JNI_VERSION;            args.name = name;            args.group = NULL;            if ((*myVm)->AttachCurrentThread(myVm, &env, &args) != JNI_OK)                return NULL;            /* Set the attached env to the thread-specific data area (TSD) */            if (pthread_setspecific(jni_env_key, env) != 0) {                (*myVm)->DetachCurrentThread(myVm);                return NULL;            }        }    }    return env;}/** * java文件在执行System.loadLibrary("hello-jni"); 的时候会调用此方法 */jint JNI_OnLoad(JavaVM *vm, void *reserved) {    JNIEnv *env = NULL;    // Keep a reference on the Java VM.    myVm = vm;    if ((*vm)->GetEnv(vm, (void **) &env, _JNI_VERSION) != JNI_OK)        return -1;    /* Create a TSD area and setup a destroy callback when a thread that     * previously set the jni_env_key is canceled or exited */    if (pthread_key_create(&jni_env_key, jni_detach_thread) != 0)        return -1;    return _JNI_VERSION;}void Java_com_example_hellojni_HelloJni_setValueSetCallback(JNIEnv *env, jobject thiz,jobject callback) {    if (callback_obj != NULL)        (*env)->DeleteGlobalRef(env, callback_obj);    //callback就是java层传进来的回调事件,在这里赋值给一个全局变量    callback_obj = callback ? (*env)->NewGlobalRef(env, callback) : NULL;}//内部回调处理函数void jni_callback(jstring value) {    JNIEnv *env;    if (!(env = jni_get_env(THREAD_NAME)))        return;    if (callback_obj == NULL) {        return;    }    //GetObjectClass是通过传入jni中的一个java的引用来获取该引用的类型。    //FindClass是通过传java中完整的类名来查找java的class,    jclass cls = (*env)->GetObjectClass(env, callback_obj);    //根据class以及方法名、参数信息获取medthodId    //onValueSet就是方法名称,(Ljava/lang/String;)V中的Ljava/lang/String;代表该方法的参数类型,V代表Void,是方法返回类型    //如果一个方法名称为abc,有两个int参数,返回值为String则应该写作:(*env)->GetMethodID(env, cls, "abc", "(II)Ljava/lang/String")    jmethodID methodId = (*env)->GetMethodID(env, cls, "onValueSet", "(Ljava/lang/String;)V");    //根据methodId执行这个方法,最后的value是参数,注意这个value必须为jstring类型的,否则报错    (*env)->CallVoidMethod(env, callback_obj, methodId, value);    //清除cls引用    (*env)->DeleteLocalRef(env, cls);}void Java_com_example_hellojni_HelloJni_setValue(JNIEnv *env, jobject thiz, jstring value) {//    char *tmp = (*env)->GetStringUTFChars(env, value, NULL);    jni_callback(value);}

在这个例子中不设置JavaVM *myVm这个全局变量也可以,直接将setValue中的env变量传给jni_callback也可以,这里全局变量是应对异步操作的情况。

java类型对应的类型签名列表:

java类型 类型签名 boolean Z byte B char C short S int I long L float F double B 类 L全限定名;,比如String, 其签名为Ljava/lang/util/String; 数组 [类型签名, 比如 [B
0 0
原创粉丝点击