JNI中创建新的线程回调java方法的技巧
在实际项目中,经常需要在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方法的技巧相关推荐
- android JNI层线程回调Java函数
今天,简单讲讲android的jni如何使用jni回调java函数. 之前,我写了部分jni的博客,讲的都是如何从android的java代码调用jni的函数.最近,需要做一个新的功能,在jni的C函 ...
- java中如何启动一个新的线程三种方法
java开启新线程的三种方法: 方法1:继承Thread类 1):定义bai一个继承自Java.lang.Thread类的du类A. 2):覆盖zhiA类Thread类中的run方法. 3):我们编写 ...
- android源码中的ndk,如何在不需要Android操作系统源代码的情况下在Android NDK中创建新的NativeWindow?...
我想编译一个Android OpenGL控制台应用程序,您可以直接从控制台启动Android x86或从Android x86 GUI中的Android终端应用程序运行.如何在不需要Android操作 ...
- 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 官方教程: ...
- 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中创建新 ...
- 计算机如果添加新用户名,怎么在电脑中创建新用户
怎么在电脑中创建新用户 我们在使用电脑的时候,一般是会设置账号并添加密码的,今天小编跟大家分享的是怎么在电脑中创建新用户. 具体如下: 1. 首先我们打开电脑,然后点击左下方开始图标,在打开的窗口中点 ...
- 罗克韦尔AB PLC RSLogix5000中创建新项目、任务、程序和例程的具体方法和步骤
罗克韦尔AB PLC RSLogix5000中创建新项目.任务.程序和例程的具体方法和步骤 如下图所示,打开Studio 5000,然后选择"新建项目", 选择所需要组态的控制器型 ...
- 请问苹果x是如何建文件夹_Mac OS X中创建新文件夹的几种方法
在日常的生活工作中,我们经常需要创建新的文件夹,这些文件夹可以帮助我们更好的管理我们的文件和电脑.因此创建新文件夹也是每个用户都会的事,在最新的MAC OS X系统中,我们可以通过几种方法创建新文件夹 ...
- linux创建数据库Oracle用户,linux下ORACLE数据库中创建新用户
http://www.cnblogs.com/cloudwalf/archive/2008/09/04/1284033.html http://www.aiisen.com/oracle-lin ...
最新文章
- html实现圆圈逐渐放大,CSS3 简单的圆形放大旋转变换
- Android 学习历程摘要(一)
- RAMdisk保存文件方案,解决关机后无盘镜像文件没了的方案
- P9 线性系统状态空间分析-《Matlab/Simulink与控制系统仿真》程序指令总结
- ROS知识:安装rosdep中出现time out的问题
- 大学生计算机基础清考试卷,天大《计算机网络基础》4月毕业清考作业考核试题模板.doc...
- 忘记mysql root管理员帐号密码处理方法
- Linux 常用的IO接口
- PHP网络操作函数汇总
- 为什么用clojure作为storm 的主要开发语言
- 20200331:每日温度(leetcode739)
- latex 插入表格_【2020.11.30】IEEE trans英文latex写作心得和学习历程
- CCLayer中Touch事件(Standard Touch Delegate Targeted Touch Delegate)
- Acrobat Pro DC 教程,如何填写并签署 PDF 表格?
- 模型训练测试之三:yolov5 模型训练及windows部署(一)
- 计算机网络技术ui设计,UI设计小白到大神的进阶之路—入门基础篇
- 2018版苹果开发者设置内购、税务、银行问题
- java商品类_商品类目选择功能开发
- 管理仓库产品要求及“先进先出”
- 手把手教学训练MTCNN模型.
热门文章
- “ 愿我如星君如月,夜夜流光相皎洁 ...”
- hive建表(一)创建外部表
- 你学了多久 Python 并能正式工作?
- Spellman高压电源维修XRM50P50X3768电源维修PCM70N120X451
- 山东计算机二级考试时间,21年9月二级考试报考时间!31省公告已出!
- php mpdf导航栏信息,php – 我想使用mpdf在pdf中设置页眉和页脚
- xticklabel 显示下划线_[转载]matlab坐标轴属性及标注
- Gallery与Imageswitch完美结合 做相册一绝啊
- 棋盘格自动生成器——四种格式(格雷码棋盘格、圆点、二维码棋盘格)
- “顾客总是对的”,客户满意从在线客服系统开始