Jni中C层传回调函数给java层

JNI回调是指在c/c++代码中调用java函数,当在c/c++的线程中执行回调函数时,会导致回调失败。

其中一种在Android系统的解决方案是:

把c/c++中所有线程的创建,由pthread_create函数替换为由Java层的创建线程的函数AndroidRuntime::createJavaThread。

假设有c++函数:

[cpp] view plain copy
  1. void *thread_entry(void *args)
  2. {
  3. while(1)
  4. {
  5. printf("thread running...\n");
  6. sleep(1);
  7. }
  8. }
  9. void init()
  10. {
  11. pthread_t thread;
  12. pthread_create(&thread,NULL,thread_entry,(void *)NULL);
  13. }

init()函数创建一个线程,需要在该线程中调用java类Test的回调函数Receive:

[cpp] view plain copy
  1. public void Receive(char buffer[],int length){
  2. String msg = new String(buffer);
  3. msg = "received from jni callback:" + msg;
  4. Log.d("Test", msg);
  5. }

首先在c++中定义回调函数指针:

[cpp] view plain copy
  1. //test.h
  2. #include <pthread.h>
  3. //function type for receiving data from native
  4. typedef void (*ReceiveCallback)(unsigned char *buf, int len);
  5. /** Callback for creating a thread that can call into the Java framework code.
  6. *  This must be used to create any threads that report events up to the framework.
  7. */
  8. typedef pthread_t (* CreateThreadCallback)(const char* name, void (*start)(void *), void* arg);
  9. typedef struct{
  10. ReceiveCallback recv_cb;
  11. CreateThreadCallback create_thread_cb;
  12. }Callback;

再修改c++中的init和thread_entry函数:

[cpp] view plain copy
  1. //test.c
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <pthread.h>
  5. #include <sys/wait.h>
  6. #include <unistd.h>
  7. #include "test.h"
  8. void *thread_entry(void *args)
  9. {
  10. char *str = "i'm happy now";
  11. Callback cb = NULL;
  12. int len;
  13. if(args != NULL){
  14. cb = (Callback *)args;
  15. }
  16. len = strlen(str);
  17. while(1)
  18. {
  19. printf("thread running...\n");
  20. //invoke callback method to java
  21. if(cb != NULL && cb->recv_cb != NULL){
  22. cb->recv_cb((unsigned char*)str, len);
  23. }
  24. sleep(1);
  25. }
  26. }
  27. void init(Callback *cb)
  28. {
  29. pthread_t thread;
  30. //pthread_create(&thread,NULL,thread_entry,(void *)NULL);
  31. if(cb != NULL && cb->create_thread_cb != NULL)
  32. {
  33. cb->create_thread_cb("thread",thread_entry,(void *)cb);
  34. }
  35. }

然后在jni中实现回调函数,以及其他实现:

[cpp] view plain copy
  1. //jni_test.c
  2. #include <stdlib.h>
  3. #include <malloc.h>
  4. #include <jni.h>
  5. #include <JNIHelp.h>
  6. #include "android_runtime/AndroidRuntime.h"
  7. #include "test.h"
  8. #define RADIO_PROVIDER_CLASS_NAME "com/tonny/Test"
  9. using namespace android;
  10. static jobject mCallbacksObj = NULL;
  11. static jmethodID method_receive;
  12. static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
  13. if (env->ExceptionCheck()) {
  14. LOGE("An exception was thrown by callback '%s'.", methodName);
  15. LOGE_EX(env);
  16. env->ExceptionClear();
  17. }
  18. }
  19. static void receive_callback(unsigned char *buf, int len)
  20. {
  21. int i;
  22. JNIEnv* env = AndroidRuntime::getJNIEnv();
  23. jcharArray array = env->NewCharArray(len);
  24. jchar *pArray ;
  25. if(array == NULL){
  26. LOGE("receive_callback: NewCharArray error.");
  27. return;
  28. }
  29. pArray = (jchar*)calloc(len, sizeof(jchar));
  30. if(pArray == NULL){
  31. LOGE("receive_callback: calloc error.");
  32. return;
  33. }
  34. //copy buffer to jchar array
  35. for(i = 0; i < len; i++)
  36. {
  37. *(pArray + i) = *(buf + i);
  38. }
  39. //copy buffer to jcharArray
  40. env->SetCharArrayRegion(array,0,len,pArray);
  41. //invoke java callback method
  42. env->CallVoidMethod(mCallbacksObj, method_receive,array,len);
  43. //release resource
  44. env->DeleteLocalRef(array);
  45. free(pArray);
  46. pArray = NULL;
  47. checkAndClearExceptionFromCallback(env, __FUNCTION__);
  48. }
  49. static pthread_t create_thread_callback(const char* name, void (*start)(void *), void* arg)
  50. {
  51. return (pthread_t)AndroidRuntime::createJavaThread(name, start, arg);
  52. }
  53. static Callback mCallbacks = {
  54. receive_callback,
  55. create_thread_callback
  56. };
  57. static void jni_class_init_native
  58. (JNIEnv* env, jclass clazz)
  59. {
  60. method_receive = env->GetMethodID(clazz, "Receive", "([CI)V");
  61. }
  62. static int jni_init
  63. (JNIEnv *env, jobject obj)
  64. {
  65. if (!mCallbacksObj)
  66. mCallbacksObj = env->NewGlobalRef(obj);
  67. return init(&mCallbacks);
  68. }
  69. static const JNINativeMethod gMethods[] = {
  70. { "class_init_native",          "()V",          (void *)jni_class_init_native },
  71. { "native_init",                "()I",          (void *)jni_init },
  72. };
  73. static int registerMethods(JNIEnv* env) {
  74. const char* const kClassName = RADIO_PROVIDER_CLASS_NAME;
  75. jclass clazz;
  76. /* look up the class */
  77. clazz = env->FindClass(kClassName);
  78. if (clazz == NULL) {
  79. LOGE("Can't find class %s/n", kClassName);
  80. return -1;
  81. }
  82. /* register all the methods */
  83. if (env->RegisterNatives(clazz,gMethods,sizeof(gMethods)/sizeof(gMethods[0])) != JNI_OK)
  84. {
  85. LOGE("Failed registering methods for %s/n", kClassName);
  86. return -1;
  87. }
  88. /* fill out the rest of the ID cache */
  89. return 0;
  90. }
  91. jint JNI_OnLoad(JavaVM* vm, void* reserved) {
  92. JNIEnv* env = NULL;
  93. jint result = -1;
  94. LOGI("Radio JNI_OnLoad");
  95. if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
  96. LOGE("ERROR: GetEnv failed/n");
  97. goto fail;
  98. }
  99. if(env == NULL){
  100. goto fail;
  101. }
  102. if (registerMethods(env) != 0) {
  103. LOGE("ERROR: PlatformLibrary native registration failed/n");
  104. goto fail;
  105. }
  106. /* success -- return valid version number */
  107. result = JNI_VERSION_1_4;
  108. fail:
  109. return result;
  110. }

jni的Android.mk文件中共享库设置为:

[cpp] view plain copy
  1. LOCAL_SHARED_LIBRARIES := liblog libcutils libandroid_runtime libnativehelper

最后再实现Java中的Test类:

[java] view plain copy
  1. //com.tonny.Test.java
  2. public class Test {
  3. static{
  4. try {
  5. System.loadLibrary("test");
  6. class_init_native();
  7. } catch(UnsatisfiedLinkError ule){
  8. System.err.println("WARNING: Could not load library libtest.so!");
  9. }
  10. }
  11. public int initialize() {
  12. return native_radio_init();
  13. }
  14. public void Receive(char buffer[],int length){
  15. String msg = new String(buffer);
  16. msg = "received from jni callback" + msg;
  17. Log.d("Test", msg);
  18. }
  19. protected  static native void class_init_native();
  20. protected  native int native_init();
  21. }

在android的jni线程C传回调函数给java相关推荐

  1. 进程池、线程池、回调函数、协程

    阅读目录 摘要: 进程池与线程池 同步调用和异步调用 回调函数 协程 一.进程池与线程池: 1.池的概念: 不管是线程还是进程,都不能无限制的开下去,总会消耗和占用资源. 也就是说,硬件的承载能力是有 ...

  2. 来自Android客户端什么意思,如何通过回调函数中的Node.js来自Android客户端

    我想从插座Android客户端将数据发送到服务器的Node.js .. 在服务器端做了什么香港专业教育学院:如何通过回调函数中的Node.js来自Android客户端 socket.on('new u ...

  3. 回调函数、Java接口回调 总结

    回调函数 谈到回调,我们得先从回调函数说起,什么叫回调函数呢? 回调函数是什么? 百度百科的解释:回调函数就是一个通过函数指针调用的函数.如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针 ...

  4. 回调函数之Java/C++版本

    本来想写一篇分析回调函数的文章,看了很多资料,未得到大一统的结论. 但基本上,Java用接口,C++用函数指针实现.可是真正统一的写法没有,场合不同实现也不一致,所以这里只抓思想,不谈具体实现.思想基 ...

  5. 【Android 高性能音频】AAudio 音频流 PCM 采样 的 采样 缓冲 播放 的 连续机制 ( 数据回调机制 | 数据回调函数指针 | 实现数据回调函数 | 设置数据回调函数 )

    文章目录 I . AAudio 音频流 采样 缓冲 播放 的连续机制 II . AAudio 音频流 数据回调函数 函数指针类型定义 III . AAudio 音频流 数据回调函数 实现 IV . A ...

  6. java 自定义函数的调用_Java/Android中的函数调用回调函数自定义回调函数

    在做Android自定义控件时遇到要自定义回调函数的问题,想想自己还暂时没有那么精深的技术,赶紧返过头回来再重新研究Java中回调函数的问题.然而不幸的是,网上太多杂乱的帖子和博客都是转来转去,而且都 ...

  7. Android和Java中的回调函数

    在 Android 的学习过程中遇到了回调函数,经过一段时间的理解,将自己的收获整理如下,希望对迫切希望了解这方面知识的同学有所启发. 回调函数的理解如下: 在A类中定义了一个方法,这个方法中用到了一 ...

  8. C++中 线程函数为静态函数 及 类成员函数作为回调函数(转载)

    C++中 线程函数为静态函数 及 类成员函数作为回调函数 线程函数为静态函数: 线程控制函数和是不是静态函数没关系,静态函数是在构造中分配的地址空间,只有在析构时才释放也就是全局的东西,不管线程是否运 ...

  9. 把C++类成员方法直接作为线程回调函数

    我以前写线程时要么老老实实照着声明写,要么使用C++类的静态成员函数来作为回调函数,经常会因为线程代码而破坏封装.之前虽然知道类成员函数的展开形式,但从没想过利用过它,昨天看深入ATL时无意中学会了这 ...

最新文章

  1. centos安装mysql密码_centos 安装mysql并设置密码
  2. Spring MVC的GET与POST请求url-pattern坑
  3. vector, list, map在遍历时删除符合条件的元素
  4. java猜数游戏图形界面_Java做一个猜数的小游戏
  5. CHM不能正常显示内容
  6. 不搞虚的!快速把你拉入Docker 的门里 | 原力计划
  7. 一次性搭建Hadoop高可用集群
  8. 一级倒立摆MATLAB仿真程序(搬运)
  9. 台式计算机屏幕出现数字模拟,电脑显示器黑屏左上角显示数字模拟什么回事
  10. SSM用户注册登录案例
  11. 计算机组成原理实验 实验四:多周期CPU实验要求(源代码全)
  12. C++ 基础练习 圆的面积
  13. Cypress自动化测试:type
  14. 华为荣耀3c手机语言设置在哪个文件夹,(科普)详解Android系统SD卡各类文件夹名称...
  15. 520男生送什么礼物好、实用小礼物合集
  16. 看完比尔盖茨30年的56条思考,我才理解他为什么能17年斩获世界首富!
  17. [ 江枫]关于ORA_ROWSCN
  18. 计算机控制技术俞光昀练习答案,计算机控制技术 复习重点 ( 俞光昀)
  19. 计算机与广告设计论文,广告设计广告论文,关于计算机广告设计的前景相关参考文献资料-免费论文范文...
  20. 阿里内部使用的12 款开发工具,很多人可能都没听过

热门文章

  1. C++:STL之vector,deque对比
  2. 做了一个验证码识别的网站
  3. Eclipse中Latex配置
  4. 词形变换和词干提取工具(英文)
  5. e人e本 html文件上传乱码,打印操作规范引发的乱码故障怎么处理
  6. halcon学习之颜色与纹理
  7. mysql报错1200_关于MYSQL配置replicate出现1200错误_MySQL
  8. 移位 c语言一个变量存储两个值,【杭州C  培训】C语言中基础小问题总结
  9. mt6761v/cbb处理器相当于骁龙多少?_三星S21骁龙版首个跑分成绩出炉 骁龙875或非正式名称...
  10. ABP之Javascript生成