在实际项目中,经常需要在Native层创建新的线程处理一些耗时操作,然后将结果回调给java层.如果按照普通的方式,直接获取MethodID,然后新线程中调用CallxxxMethod(),这样肯定是行不通的.当你看到这篇文章时,相信你已经 踩到这个坑了.下面将介绍如何在Native层线程中回调java方法.

Java代码
public class MainActivity extends AppCompatActivity {// Used to load the 'native-lib' library on application startup.static {System.loadLibrary("native");}private TextView tv;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// Example of a call to a native methodtv = (TextView) findViewById(R.id.sample_text);tv.setText("Native Update: 0");}@Overrideprotected void onStart() {super.onStart();createNativeThread();}@Overrideprotected void onStop() {super.onStop();releaseNativeThread();}//在jni层创建一个线程public native void createNativeThread();//jni层线程退出释放资源public native void releaseNativeThread();//该函数会被jni创建的新线程回调public void callbackFromJNI(int arg){final int i = arg;runOnUiThread(new Runnable() {@Overridepublic void run() {tv.setText("Native Update: "+ i);}});Log.d("test",String.format("arg:%d",arg));}
}C代码:
#include <pthread.h>
#include "fflog.h"//记录类相关的信息
typedef struct ClassInfo {JavaVM *jvm;   //保存java虚拟机,这是在新线程中能够回调到java方法的最重要的参数.jobject obj;   //保存java对象jmethodID callbackMethodId; //保存methodID
}ClassInfo;//定义一个全局的ClassInfo
ClassInfo gClassInfo = {0};//该函数用来在线程中调用, callback函数用来调用java方法
void callback(int i)
{JNIEnv *env;//通过jvm的接口,attach到当前线程,同时该函数还会获取到所需的env变量. (*gClassInfo.jvm)->AttachCurrentThread(gClassInfo.jvm, &env, NULL);//回调java方法 (*env)->CallVoidMethod(env, gClassInfo.obj, gClassInfo.callbackMethodId, i); //调用完之后,detach. (*gClassInfo.jvm)->DetachCurrentThread(gClassInfo.jvm);}//线程工作函数
int quit;
//用来退出线程循环,实际项目,尽量不要使用全局变量
void* work(void *arg) { LOGFD("native thread begin..."); int i = 0; quit = 0; while(1) { if(quit) { break; } i++; callback(i); //sleep 一秒表示耗时操作.实际使用时添加需要处理代码. sleep(1); } LOGFD("native thread exit...");
}JNIEXPORT void JNICALLJava_com_example_nativethreadcallbackdemo_MainActivity_createNativeThread(JNIEnv *env, jobject instance)
{ BEGIN /** 说明:在jni层如果有多线程,实际上JNIEnv(jni环境变量)是不能够在多线程中共用的, env只能在当前线程有效, * 但是JavaVM可以,JavaVM指Java虚拟机,这个变量是进程可共用的.所以要想在其他线程中回调java方法,需要保存的是jvm. */ (*env)->GetJavaVM(env, &gClassInfo.jvm); jclass cls = (*env)->FindClass(env, "com/example/nativethreadcallbackdemo/MainActivity"); CHECK_NULL(cls) //获取MethodID gClassInfo.callbackMethodId = (*env)->GetMethodID(env, cls, "callbackFromJNI", "(I)V"); CHECK_NULL(gClassInfo.callbackMethodId) /** 说明:为了能够在其它线程得到java的对象,必须要instance转化为全局对象,这样在其它线程才能得到当前java对象的索引. * 否则在其它线程要用到当前java对象时,会出现无效引用的错误. */ gClassInfo.obj = (*env)->NewGlobalRef(env, instance); CHECK_NULL(gClassInfo.obj) //创建一个线程 pthread_t pid; pthread_create(&pid, NULL, work, NULL); END
}JNIEXPORT void JNICALLJava_com_example_nativethreadcallbackdemo_MainActivity_releaseNativeThread(JNIEnv *env, jobject instance)
{ quit = 1; (*env)->DeleteGlobalRef(env, gClassInfo.obj); gClassInfo.obj = NULL;
}

http://download.csdn.NET/detail/yuzhihui170/9799272

JNI中创建新的线程回调java方法的技巧相关推荐

  1. android JNI层线程回调Java函数

    今天,简单讲讲android的jni如何使用jni回调java函数. 之前,我写了部分jni的博客,讲的都是如何从android的java代码调用jni的函数.最近,需要做一个新的功能,在jni的C函 ...

  2. java中如何启动一个新的线程三种方法

    java开启新线程的三种方法: 方法1:继承Thread类 1):定义bai一个继承自Java.lang.Thread类的du类A. 2):覆盖zhiA类Thread类中的run方法. 3):我们编写 ...

  3. android源码中的ndk,如何在不需要Android操作系统源代码的情况下在Android NDK中创建新的NativeWindow?...

    我想编译一个Android OpenGL控制台应用程序,您可以直接从控制台启动Android x86或从Android x86 GUI中的Android终端应用程序运行.如何在不需要Android操作 ...

  4. asp.net mysql 创建变_[ASP.net教程]EF Core使用CodeFirst在MySql中创建新数据库以及已有的Mysql数据库如何使用DB First生成域模型...

    [ASP.net教程]EF Core使用CodeFirst在MySql中创建新数据库以及已有的Mysql数据库如何使用DB First生成域模型 0 2018-06-30 07:00:08 官方教程: ...

  5. ef mysql 数据模型,EF Core使用CodeFirst在MySql中创建新数据库以及已有的Mysql数据库如何使用DB First生成域模型...

    官方教程:https://docs.microsoft.com/en-us/aspnet/core/data/?view=aspnetcore-2.1 使用EF CodeFirst在MySql中创建新 ...

  6. 计算机如果添加新用户名,怎么在电脑中创建新用户

    怎么在电脑中创建新用户 我们在使用电脑的时候,一般是会设置账号并添加密码的,今天小编跟大家分享的是怎么在电脑中创建新用户. 具体如下: 1. 首先我们打开电脑,然后点击左下方开始图标,在打开的窗口中点 ...

  7. 罗克韦尔AB PLC RSLogix5000中创建新项目、任务、程序和例程的具体方法和步骤

    罗克韦尔AB PLC RSLogix5000中创建新项目.任务.程序和例程的具体方法和步骤 如下图所示,打开Studio 5000,然后选择"新建项目", 选择所需要组态的控制器型 ...

  8. 请问苹果x是如何建文件夹_Mac OS X中创建新文件夹的几种方法

    在日常的生活工作中,我们经常需要创建新的文件夹,这些文件夹可以帮助我们更好的管理我们的文件和电脑.因此创建新文件夹也是每个用户都会的事,在最新的MAC OS X系统中,我们可以通过几种方法创建新文件夹 ...

  9. linux创建数据库Oracle用户,linux下ORACLE数据库中创建新用户

     http://www.cnblogs.com/cloudwalf/archive/2008/09/04/1284033.html http://www.aiisen.com/oracle-lin ...

最新文章

  1. html实现圆圈逐渐放大,CSS3 简单的圆形放大旋转变换
  2. Android 学习历程摘要(一)
  3. RAMdisk保存文件方案,解决关机后无盘镜像文件没了的方案
  4. P9 线性系统状态空间分析-《Matlab/Simulink与控制系统仿真》程序指令总结
  5. ROS知识:安装rosdep中出现time out的问题
  6. 大学生计算机基础清考试卷,天大《计算机网络基础》4月毕业清考作业考核试题模板.doc...
  7. 忘记mysql root管理员帐号密码处理方法
  8. Linux 常用的IO接口
  9. PHP网络操作函数汇总
  10. 为什么用clojure作为storm 的主要开发语言
  11. 20200331:每日温度(leetcode739)
  12. latex 插入表格_【2020.11.30】IEEE trans英文latex写作心得和学习历程
  13. CCLayer中Touch事件(Standard Touch Delegate Targeted Touch Delegate)
  14. Acrobat Pro DC 教程,如何填写并签署 PDF 表格?
  15. 模型训练测试之三:yolov5 模型训练及windows部署(一)
  16. 计算机网络技术ui设计,UI设计小白到大神的进阶之路—入门基础篇
  17. 2018版苹果开发者设置内购、税务、银行问题
  18. java商品类_商品类目选择功能开发
  19. 管理仓库产品要求及“先进先出”
  20. 手把手教学训练MTCNN模型.

热门文章

  1. “ 愿我如星君如月,夜夜流光相皎洁 ...”
  2. hive建表(一)创建外部表
  3. 你学了多久 Python 并能正式工作?
  4. Spellman高压电源维修XRM50P50X3768电源维修PCM70N120X451
  5. 山东计算机二级考试时间,21年9月二级考试报考时间!31省公告已出!
  6. php mpdf导航栏信息,php – 我想使用mpdf在pdf中设置页眉和页脚
  7. xticklabel 显示下划线_[转载]matlab坐标轴属性及标注
  8. Gallery与Imageswitch完美结合 做相册一绝啊
  9. 棋盘格自动生成器——四种格式(格雷码棋盘格、圆点、二维码棋盘格)
  10. “顾客总是对的”,客户满意从在线客服系统开始