博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
JNI多线程与全局引用
阅读量:6243 次
发布时间:2019-06-22

本文共 5008 字,大约阅读时间需要 16 分钟。

之前的JNI学习文章中有介绍过全局变量,在本文中将派上用用场,直接使用。

本次实战主要是在C层开辟子线程,然后通过访问java类,获取得到UUID,并且打印出来。

具体步骤:

1、创建一个NDK项目,编写native方法 NDKTest.java

public class NDKTest {	public native static String getStrFromJNI();//测试	public native void pthread();	public native void init();	public native void destroy();	static {		System.loadLibrary("myndk");	}}复制代码

init也就是初始化,主要是获取class,通过class获取jmethodID等操作。

pthread:创建线程,访问类的方法。

destroy:释放资源

2、编写方法获取UUID

public class UUIDUtils {	public static String get(){		return UUID.randomUUID().toString();	}}复制代码

3、通过javah获得头文件com_example_ndkfile_NDKTest.h

/* DO NOT EDIT THIS FILE - it is machine generated */#include 
/* Header for class com_example_ndkfile_NDKTest */#ifndef _Included_com_example_ndkfile_NDKTest#define _Included_com_example_ndkfile_NDKTest#ifdef __cplusplusextern "C" {#endif/* * Class: com_example_ndkfile_NDKTest * Method: getStrFromJNI * Signature: ()Ljava/lang/String; */JNIEXPORT jstring JNICALL Java_com_example_ndkfile_NDKTest_getStrFromJNI (JNIEnv *, jclass);//初始化JNIEXPORT void JNICALL Java_com_example_ndkfile_NDKTest_init (JNIEnv *, jobject);//销毁JNIEXPORT void JNICALL Java_com_example_ndkfile_NDKTest_destroy (JNIEnv *, jobject);//创建线程JNIEXPORT void JNICALL Java_com_example_ndkfile_NDKTest_pthread (JNIEnv *, jobject);#ifdef __cplusplus}#endif#endif复制代码

4、创建.c文件

5、项目右键--->Android Tools------->add native support

6、配置Android.mk

LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE    := myndkLOCAL_SRC_FILES := myndk.cLOCAL_LDLIBS := -lloginclude $(BUILD_SHARED_LIBRARY)复制代码

7、在myndk.c实现com_example_ndkfile_NDKTest.h函数。

我们知道每个线程都有独立的JNIEnv,那么如何获取JNIEnv? 首先JavaVM 代表的是Java虚拟机,所有的工作都是从JavaVM开始,可以通过JavaVM获取到每个线程关联的JNIEnv。 那么又如何如何获取JavaVM?

1)、在JNI_OnLoad函数中获取,每次运行jni系统就会首先自动调用JNI_OnLoad函数。

2)、(*env)->GetJavaVM(env,&javaVM);

这里我们通过JNI_OnLoad获取:

JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved){	LOGI("%s","JNI_OnLoad");	javaVM = vm;	return JNI_VERSION_1_4;}复制代码

myndk.c:

#include "com_example_ndkfile_NDKTest.h"#include 
#include
#include
#include
#include
#define LOGI(FORMAT,...) __android_log_print(ANDROID_LOG_INFO,"test",FORMAT,##__VA_ARGS__);#define LOGE(FORMAT,...) __android_log_print(ANDROID_LOG_ERROR,"test",FORMAT,##__VA_ARGS__);JavaVM *javaVM;jobject uuidutils_class_global;jmethodID uuidutils_get_mid;//动态库加载时会执行//兼容Android SDK 2.2之后,2.2没有这个函数JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved){ LOGI("%s","JNI_OnLoad"); javaVM = vm; return JNI_VERSION_1_4;}JNIEXPORT jstring JNICALL Java_com_example_ndkfile_NDKTest_getStrFromJNI (JNIEnv *env, jclass jcls){ return (*env)->NewStringUTF(env,"hello formjni");}void* th_fun(void* arg){ int i; for (i = 0; i < 5; i++) { JNIEnv* env; //关联参数 //JavaVMAttachArgs args = {JNI_VERSION_1_4, "my_thread", NULL}; //(*javaVM)->AttachCurrentThread(javaVM,&env,&args); (*javaVM)->AttachCurrentThread(javaVM,&env,NULL); jobject uuid_jstr = (*env)->CallStaticObjectMethod(env,uuidutils_class_global,uuidutils_get_mid); const char* uuid_cstr = (*env)->GetStringUTFChars(env,uuid_jstr,NULL); LOGI("uuid:%s",uuid_cstr); //退出线程 if(i == 4){ goto end; } sleep(1); }end: //取消关联 (*javaVM)->DetachCurrentThread(javaVM); pthread_exit((void*)0);}//初始化JNIEXPORT void JNICALL Java_com_example_ndkfile_NDKTest_init(JNIEnv *env, jobject jobj){ //获取class必须要在主线程中 jclass uuidutils_class_tmp = (*env)->FindClass(env,"com/example/ndkfile/UUIDUtils"); //创建全局引用 uuidutils_class_global = (*env)->NewGlobalRef(env,uuidutils_class_tmp); //获取jmethodId也可以在子线程中 uuidutils_get_mid = (*env)->GetStaticMethodID(env,uuidutils_class_global,"get","()Ljava/lang/String;");}//创建线程JNIEXPORT void JNICALL Java_com_example_ndkfile_NDKTest_pthread(JNIEnv *env, jobject jobj){ //(*env)->GetJavaVM(env,&javaVM); //创建多线程 pthread_t tid; pthread_create(&tid, NULL,th_fun,(void*)"NO1");}//销毁JNIEXPORT void JNICALL Java_com_example_ndkfile_NDKTest_destroy(JNIEnv *env, jobject jobj){ //释放全局引用 (*env)->DeleteGlobalRef(env,uuidutils_class_global);}复制代码

1)、在初始化的时候还通过了(*env)->NewGlobalRef创建全局引用,在销毁的时候需要通过(*env)->DeleteGlobalRef释放全局引用。

2)、通过以下语句创建多线程,而th_fun方法就是运行在子线程中。

pthread_t tid; pthread_create(&tid, NULL,th_fun,(void*)"NO1");

调用

MainActivity:

public class MainActivity extends Activity {	private TextView mTextView;	private NDKTest ndktest;		@Override	protected void onCreate(Bundle savedInstanceState) {		super.onCreate(savedInstanceState);		setContentView(R.layout.activity_main);		mTextView = (TextView)this.findViewById(R.id.mytext);		mTextView.setText(NDKTest.getStrFromJNI());				ndktest = new NDKTest();		ndktest.init();				mTextView.setOnClickListener(new View.OnClickListener() {						@Override			public void onClick(View v) {				// TODO Auto-generated method stub				ndktest.pthread();			}		});			}	@Override	protected void onDestroy() {		// TODO Auto-generated method stub		super.onDestroy();		ndktest.destroy();	}}复制代码

注意: 需要在onCreate中调用init,在onDestroy调用destroy

运行结果:

从结果中我们看到了,确实通过JNI多线程访问java类获取得到了UUID。

转载地址:http://tppia.baihongyu.com/

你可能感兴趣的文章
VR技术行业应用前景初探:技术创新定义精彩未来
查看>>
知识产权攻击是从哪冒出来的?
查看>>
宽带服务商设局,美国法律这么治
查看>>
混合IT架构的最佳实践
查看>>
一文详解神经网络 BP 算法原理及 Python 实现
查看>>
高通与联想达成新专利许可协议
查看>>
阿里科学家王刚、吴翰清同时入选MIT2017年度TR35 开创中国互联网企业先河
查看>>
继SDS之后又迎来CDM,存储行业真要变天了?
查看>>
美媒:联想电脑威胁五角大楼网络安全
查看>>
绿色智慧城市|城市增长边界的几个误区
查看>>
美国土安全部发警告:尽快卸载QuickTime for Windows
查看>>
《SEO的艺术(原书第2版)》——3.9 为客户挖掘和直接营销开展SEO
查看>>
运营商造梦“管道+内容”三十载不言放弃
查看>>
《 自动化测试最佳实践:来自全球的经典自动化测试案例解析》一一3.1 本案例研究的背景...
查看>>
哈工大在CoNLL上斩获全球第四,车万翔博士详解背后的技术细节
查看>>
阿里钉钉VS企业微信 谁才是企业级一哥?
查看>>
2015-2020智慧城市物联网市场复合年增长率达23.2%
查看>>
做好数据分析让物联网数据价值最大化
查看>>
OpenStack Days走进北京 主角是用户
查看>>
JVM问题诊断常用命令:jinfo,jmap,jstack
查看>>