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类型对应的类型签名列表:
0 0
- EasyDarwin安卓直播之EasyPusher NDK开发:JNI回调函数的实现
- EasyPusher安卓直播推流到EasyDarwin开源流媒体服务器工程简析
- 基于EasyDarwin EasyPusher实现Android手机直播推送功能
- EasyPusher/EasyDarwin/EasyPlayer实现手机直播版本及效果整理
- EasyPusher/EasyDarwin/EasyPlayer实现手机直播版本及效果整理
- 安卓NDK开发之快速熟悉JNI参数的回调
- 安卓开发中的回调函数
- EasyDarwin相关Android安卓客户端EasyPusher/EasyPlayer/EasyCamera/EasyClient在无开发环境进行log抓取
- EasyPusher实现安卓Android手机直播推送同步录像功能(源码解析)
- [转]EasyPusher实现安卓Android手机直播推送同步录像功能(源码解析)
- EasyPusher安卓Android手机直播推送之MediaCodec 硬编码H264格式
- EasyPusher安卓Android手机直播推送之MediaCodec 硬编码H264格式
- EasyPusher安卓Android手机直播推送之RTSP流媒体协议流程
- EasyPusher安卓手机直播之音频采集与AAC编码
- EasyPusher安卓Android手机直播推送之MediaCodec 硬编码H264格式
- EasyPusher安卓Android手机直播推送之MediaCodec 硬编码H264格式
- 安卓NDK开发之快速熟悉JNI参数的传递
- JNI回调函数
- 树莓派派配置PPTP
- Openstack学习笔记(七)-在Win环境下通过XManager(xshell)远程打开eclipse
- Linux内核分析之七——Linux内核如何装载和启动一个可执行程序
- uva 340 Master-Mind Hints
- 给你日期求那天是星期几
- EasyDarwin安卓直播之EasyPusher NDK开发:JNI回调函数的实现
- The 16th Zhejiang University Programming Contest - E
- Scrapy设置之Downloading media
- TangowithDjango--Start
- 第6周
- Android电子书阅读器的设计与实现
- Mysql安装与配置总结
- java正则表达式
- 关于微信分享接口开发