博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android开发实践:JNI层线程回调Java函数示例
阅读量:5108 次
发布时间:2019-06-13

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

原创作品,允许转载,转载时请务必以超链接形式标明文章 、作者信息和本声明。否则将追究法律责任。

JNI是Java Native Interface的缩写,是Java平台的重要特性,使得Java代码可以方便地与C/C++代码编译生成的动态链接库进行交互。本文主要给出一份示例代码(工程文件见附件),描述如何在Android的JNI层开启一个线程,并在线程中回调Java层的函数。

 

代码主要分为Java层(java代码)和JNI层(c语言代码),首先看看Java层的代码(Native.java)。

 

 

如上所示,Java层与JNI层的接口代码主要封装在Native类中,该类定义了三个native函数,分别完成jni库的初始化,调用jni层开启线程,调用jni层关闭线程等功能。并且提供一个回调函数(onNativeCallback),供jni层调用,并在回调函数中打印count的值。

 

再看看JNI层是如何开启线程并回调Java层的(native.c),关键的地方都在代码中进行了注释:

native C实现:

   1. 头文件包含和全局变量的定义

           

         

   2. 初始化函数的实现

             

 

   3. 开启关闭线程的实现

 

                                           

 4. 线程的实现(关键)

 

 

native C++实现

#include <jni.h>

#include <android/log.h>
#include <pthread.h>
#include <unistd.h>
#define TAG "JniNative"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,TAG,__VA_ARGS__)
JavaVM *gJavaVM;
jobject gJavaObj;
int volatile gIsThreadStop = 0;
static const char *classPath = "com/jni/test/JniNativeCallback";
static void* native_thread_exec(void *arg)
{
    LOGI("nativeThreadExec");
    JNIEnv *env;
    //get env From gJavaVm
    gJavaVM->AttachCurrentThread(&env,NULL);
    //get Java class by classPath
//    jclass thiz = env->FindClass(classPath);
    jclass thiz = env->GetObjectClass(gJavaObj);
    //get Java method from thiz
    jmethodID nativeCallback = env->GetMethodID(thiz,"nativeCallback","(I)V");
    int count = 0;
    while(!gIsThreadStop)
    {
        sleep(2);
        //env->CallVoidMethod(thiz,nativeCallback,count++);
        env->CallVoidMethod(gJavaObj,nativeCallback,count++);
    }
    gJavaVM->DetachCurrentThread();
    LOGI("thread stoped");
}
JNIEXPORT void JNICALL native_init(JNIEnv *env,jobject thiz)
{
    LOGI("native_init");
    gIsThreadStop = 0;
    env->GetJavaVM(&gJavaVM);
    gJavaObj = env->NewGlobalRef(thiz);
}
JNIEXPORT void JNICALL native_thread_start(JNIEnv *env,jobject jthiz)
{
    LOGI("native_thread_start");
    gIsThreadStop = 0;
    pthread_t id;
    if(pthread_create(&id,NULL,native_thread_exec,NULL)!=0)
    {
        LOGI("native thread create fail");
        return;
    }
    LOGI("native thread creat success");
}
JNIEXPORT void JNICALL native_thread_stop(JNIEnv *env,jobject jthiz)
{
    gIsThreadStop = 1;
    LOGI("native_thread_stop");
}
static JNINativeMethod methods[] = {
        {"nativeInit","()V",(void*)native_init},
        {"nativeThreadStart","()V",(void*)native_thread_start},
        {"nativeThreadStop","()V",(void*)native_thread_stop}
};
jint JNI_OnLoad(JavaVM *vm, void *reserve)
{
    LOGI("JNI_OnLoad");
    JNIEnv *env;
    if(vm->GetEnv((void**)&env,JNI_VERSION_1_4)!=JNI_OK)
    {
        return -1;
    }
    jclass jthiz = env->FindClass(classPath);
    if(env->RegisterNatives(jthiz,methods,sizeof(methods)/sizeof(methods[0]))<0)
    {
        return -1;
    }
    return JNI_VERSION_1_4;
}

 

 

 

   由上述代码可以看到,JNI层通过pthread库完成了线程的创建,需要特别注意的是,JNI层的线程中,必须通过全局的JavaVM来获取到环境变量,也必须通过全局的jobject获取java类对象,从而找到java端的函数,进行回调。

转载于:https://www.cnblogs.com/seven-sky/p/7205932.html

你可能感兴趣的文章
c#运算符 ?
查看>>
【题解】青蛙的约会
查看>>
求给定字符串的最长子字符串
查看>>
.26-浅析webpack源码之事件流make(1)
查看>>
IO流
查看>>
mybatis调用存储过程,获取返回的游标
查看>>
设计模式之装饰模式(结构型)
查看>>
面向对象的设计原则
查看>>
Swift3.0服务端开发(三) Mustache页面模板与日志记录
查看>>
【转】 FPGA设计的四种常用思想与技巧
查看>>
C++:同名隐藏和赋值兼容规则
查看>>
EntityFrameWork 实现实体类和DBContext分离在不同类库
查看>>
新手算法学习之路----二叉树(在一个二叉查找树中插入一个节点)
查看>>
autopep8
查看>>
GIT在Linux上的安装和使用简介
查看>>
基于C#编程语言的Mysql常用操作
查看>>
【转】Java反射 之 反射基础
查看>>
mysql数据库备份和还原的常用命令
查看>>
s3c2440实验---定时器
查看>>
HBase配置性能调优(转)
查看>>