项目目录

CMakeLists.txt

cmake_minimum_required(VERSION 3.4.1)add_library(hello-jnicallback SHAREDhello-jnicallback.c)# Include libraries needed for hello-jnicallback lib
target_link_libraries(hello-jnicallbackandroidlog)

hello-jnicallback.c

#include <string.h>
#include <inttypes.h>
#include <pthread.h>
#include <jni.h>
#include <android/log.h>
#include <assert.h>// Android log function wrappers,对android log进行了封装
static const char* kTAG = "hello-jniCallback";
#define LOGI(...) \((void)__android_log_print(ANDROID_LOG_INFO, kTAG, __VA_ARGS__))
#define LOGW(...) \((void)__android_log_print(ANDROID_LOG_WARN, kTAG, __VA_ARGS__))
#define LOGE(...) \((void)__android_log_print(ANDROID_LOG_ERROR, kTAG, __VA_ARGS__))// processing callback to handler class,上下文
typedef struct tick_context {JavaVM  *javaVM;jclass   jniHelperClz;--------->对应于JniHandlerjobject  jniHelperObj;jclass   mainActivityClz;------>对应于MainActivityjobject  mainActivityObj;pthread_mutex_t  lock;int      done;
} TickContext;
TickContext g_ctx;/* This is a trivial JNI example where we use a native method* to return a new VM String. See the corresponding Java source* file located at:**   hello-jniCallback/app/src/main/java/com/example/hellojnicallback/MainActivity.java*/
JNIEXPORT jstring JNICALL
Java_com_example_hellojnicallback_MainActivity_stringFromJNI( JNIEnv* env, jobject thiz )
{return (*env)->NewStringUTF(env, "Hello from JNI !  Compiled with ABI " ABI ".");
}/**  A helper function to show how to call*     java static functions JniHelper::getBuildVersion()*     java non-static function JniHelper::getRuntimeMemorySize()*  The trivial implementation for these functions are inside file*     JniHelper.java这个展示了如何调用java的静态方法,非静态方法。*/
void queryRuntimeInfo(JNIEnv *env, jobject instance) {// Find out which OS we are running on. It does not matter for this app// just to demo how to call static functions.// Our java JniHelper class id and instance are initialized when this// shared lib got loaded, we just directly use them//    static function does not need instance, so we just need to feed//    class and method id to JNIjmethodID versionFunc = (*env)->GetStaticMethodID(env, g_ctx.jniHelperClz,"getBuildVersion", "()Ljava/lang/String;");//获取静态方法if (!versionFunc) {LOGE("Failed to retrieve getBuildVersion() methodID @ line %d",__LINE__);return;}jstring buildVersion = (*env)->CallStaticObjectMethod(env,g_ctx.jniHelperClz, versionFunc);//调用静态的方法。const char *version = (*env)->GetStringUTFChars(env, buildVersion, NULL);//把jsting转换为c类型的字符串if (!version) {LOGE("Unable to get version string @ line %d", __LINE__);return;}LOGI("Android Version - %s", version);
/*
在调用 GetStringUTFChars 函数从 JVM 内部获取一个字符串之后,JVM 内部会分配一块新的内存,用于存储源字符串的拷贝,以便本地代码访问和修改。即然有内存分配,用完之后马上释放是一个编程的好习惯。通过调用ReleaseStringUTFChars 函数通知 JVM 这块内存已经不使用了,你可以清除了。注意:这两个函数是配对使用的,用了 GetXXX 就必须调用 ReleaseXXX,而且这两个函数的命名也有规律,除了前面的 Get 和 Release 之外,后面的都一样。
*/(*env)->ReleaseStringUTFChars(env, buildVersion, version);//释放jstring。/*

局部引用:

JNI 函数内部创建的 jobject 对象及其子类( jclass 、 jstring 、 jarray 等) 对象都是局部引用,它们在 JNI 函数返回后无效;

一般情况下,我们应该依赖 JVM 去自动释放 JNI 局部引用;但下面两种情况必须手动调用 DeleteLocalRef() 去释放:

  • (在循环体或回调函数中)创建大量 JNI 局部引用,即使它们并不会被同时使用,因为 JVM 需要足够的空间去跟踪所有的 JNI 引用,所以可能会造成内存溢出或者栈溢出;

  • 如果对一个大的 Java 对象创建了 JNI 局部引用,也必须在使用完后手动释放该引用,否则 GC 迟迟无法回收该 Java 对象也会引发内存泄漏.

全局引用:

全局引用允许你持有一个 JNI 对象更长的时间,直到你手动销毁;但需要显式调用 NewGlobalRef() 和 DeleteGlobalRef() 

*/// we are called from JNI_OnLoad, so got to release LocalRef to avoid leaking(*env)->DeleteLocalRef(env, buildVersion);/*

方法签名

调用JNI的GetMethodID函数获取一个jmethodID时,需要传入一个方法名称和方法签名,方法名称就是在Java中定义的方法名,方法签名的格式为:(形参参数类型列表)返回值。

*/// Query available memory size from a non-static public function// we need use an instance of JniHelper class to call JNIjmethodID memFunc = (*env)->GetMethodID(env, g_ctx.jniHelperClz,"getRuntimeMemorySize", "()J");//获取成员函数if (!memFunc) {LOGE("Failed to retrieve getRuntimeMemorySize() methodID @ line %d",__LINE__);return;}jlong result = (*env)->CallLongMethod(env, instance, memFunc);LOGI("Runtime free memory size: %" PRId64, result);(void)result;  // silence the compiler warning
}/** processing one time initialization:*     Cache the javaVM into our context*     Find class ID for JniHelper*     Create an instance of JniHelper*     Make global reference since we are using them from a native thread* Note:*     All resources allocated here are never released by application*     we rely on system to free all global refs when it goes away;*     the pairing function JNI_OnUnload() never gets called at all.*/
/*
实现JNI中本地函数注册有两种方式:1.采用默认的本地函数注册流程。2.自己重写JNI_OnLload()函数。
当Android的VM执行到C组件(*so)里的System.loadLibrary()函数时,首先会去执行C组件里的JNI_OnLoad()函数,其用途有二*/
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {JNIEnv* env;memset(&g_ctx, 0, sizeof(g_ctx));g_ctx.javaVM = vm;if ((*vm)->GetEnv(vm, (void**)&env, JNI_VERSION_1_6) != JNI_OK) {return JNI_ERR; // JNI version not supported.}jclass  clz = (*env)->FindClass(env,"com/example/hellojnicallback/JniHandler");g_ctx.jniHelperClz = (*env)->NewGlobalRef(env, clz);----->获取并保存获取的java类jmethodID  jniHelperCtor = (*env)->GetMethodID(env, g_ctx.jniHelperClz,"<init>", "()V");-------->获取int的方法jobject    handler = (*env)->NewObject(env, g_ctx.jniHelperClz,jniHelperCtor);----->使用获取的init的方法,进行构造相应的对象g_ctx.jniHelperObj = (*env)->NewGlobalRef(env, handler);queryRuntimeInfo(env, g_ctx.jniHelperObj);g_ctx.done = 0;g_ctx.mainActivityObj = NULL;return  JNI_VERSION_1_6;
}/** A helper function to wrap java JniHelper::updateStatus(String msg)* JNI allow us to call this function via an instance even it is* private function.
发送一个Java的消息*/
void   sendJavaMsg(JNIEnv *env, jobject instance,jmethodID func,const char* msg) {jstring javaMsg = (*env)->NewStringUTF(env, msg);(*env)->CallVoidMethod(env, instance, func, javaMsg);(*env)->DeleteLocalRef(env, javaMsg);
}/** Main working thread function. From a pthread,*     calling back to MainActivity::updateTimer() to display ticks on UI*     calling back to JniHelper::updateStatus(String msg) for msg两个callback,一个展示时钟在UI界面上,一个回调发送消息*/
void*  UpdateTicks(void* context) {TickContext *pctx = (TickContext*) context;JavaVM *javaVM = pctx->javaVM;JNIEnv *env;jint res = (*javaVM)->GetEnv(javaVM, (void**)&env, JNI_VERSION_1_6);if (res != JNI_OK) {res = (*javaVM)->AttachCurrentThread(javaVM, &env, NULL);if (JNI_OK != res) {LOGE("Failed to AttachCurrentThread, ErrorCode = %d", res);return NULL;}}jmethodID statusId = (*env)->GetMethodID(env, pctx->jniHelperClz,"updateStatus","(Ljava/lang/String;)V");//获取方法sendJavaMsg(env, pctx->jniHelperObj, statusId,"TickerThread status: initializing...");//发送消息正在初始化// get mainActivity updateTimer functionjmethodID timerId = (*env)->GetMethodID(env, pctx->mainActivityClz,"updateTimer", "()V");//获取更新的的方法struct timeval beginTime, curTime, usedTime, leftTime;const struct timeval kOneSecond = {(__kernel_time_t)1,(__kernel_suseconds_t) 0};sendJavaMsg(env, pctx->jniHelperObj, statusId,"TickerThread status: start ticking ...");while(1) {gettimeofday(&beginTime, NULL);pthread_mutex_lock(&pctx->lock);int done = pctx->done;if (pctx->done) {pctx->done = 0;}pthread_mutex_unlock(&pctx->lock);if (done) {break;}(*env)->CallVoidMethod(env, pctx->mainActivityObj, timerId);gettimeofday(&curTime, NULL);timersub(&curTime, &beginTime, &usedTime);timersub(&kOneSecond, &usedTime, &leftTime);struct timespec sleepTime;sleepTime.tv_sec = leftTime.tv_sec;sleepTime.tv_nsec = leftTime.tv_usec * 1000;if (sleepTime.tv_sec <= 1) {nanosleep(&sleepTime, NULL);} else {sendJavaMsg(env, pctx->jniHelperObj, statusId,"TickerThread error: processing too long!");}}sendJavaMsg(env, pctx->jniHelperObj, statusId,"TickerThread status: ticking stopped");//发送时钟消息(*javaVM)->DetachCurrentThread(javaVM);return context;
}/** Interface to Java side to start ticks, caller is from onResume()*/
JNIEXPORT void JNICALL
Java_com_example_hellojnicallback_MainActivity_startTicks(JNIEnv *env, jobject instance) {pthread_t       threadInfo_;pthread_attr_t  threadAttr_;pthread_attr_init(&threadAttr_);pthread_attr_setdetachstate(&threadAttr_, PTHREAD_CREATE_DETACHED);pthread_mutex_init(&g_ctx.lock, NULL);jclass clz = (*env)->GetObjectClass(env, instance);g_ctx.mainActivityClz = (*env)->NewGlobalRef(env, clz);g_ctx.mainActivityObj = (*env)->NewGlobalRef(env, instance);int result  = pthread_create( &threadInfo_, &threadAttr_, UpdateTicks, &g_ctx);assert(result == 0);pthread_attr_destroy(&threadAttr_);(void)result;
}/** Interface to Java side to stop ticks:*    we need to hold and make sure our native thread has finished before return*    for a clean shutdown. The caller is from onPause*/
JNIEXPORT void JNICALL
Java_com_example_hellojnicallback_MainActivity_StopTicks(JNIEnv *env, jobject instance) {pthread_mutex_lock(&g_ctx.lock);g_ctx.done = 1;pthread_mutex_unlock(&g_ctx.lock);// waiting for ticking thread to flip the done flagstruct timespec sleepTime;memset(&sleepTime, 0, sizeof(sleepTime));sleepTime.tv_nsec = 100000000;while (g_ctx.done) {nanosleep(&sleepTime, NULL);}// release object we allocated from StartTicks() function(*env)->DeleteGlobalRef(env, g_ctx.mainActivityClz);(*env)->DeleteGlobalRef(env, g_ctx.mainActivityObj);g_ctx.mainActivityObj = NULL;g_ctx.mainActivityClz = NULL;pthread_mutex_destroy(&g_ctx.lock);
}

Jnihandler.java

public class JniHandler {/** Print out status to logcat*/@Keepprivate void updateStatus(String msg) {if (msg.toLowerCase().contains("error")) {Log.e("JniHandler", "Native Err: " + msg);} else {Log.i("JniHandler", "Native Msg: " + msg);}}/** Return OS build version: a static function*/@Keepstatic public String getBuildVersion() {return Build.VERSION.RELEASE;}/** Return Java memory info*/@Keeppublic long getRuntimeMemorySize() {return Runtime.getRuntime().freeMemory();}
}

MainAcitivity.java

@Keep
private void updateTimer() {++second;if(second >= 60) {++minute;second -= 60;if(minute >= 60) {++hour;minute -= 60;}}runOnUiThread(new Runnable() {@Overridepublic void run() {String ticks = "" + MainActivity.this.hour + ":" +MainActivity.this.minute + ":" +MainActivity.this.second;MainActivity.this.tickView.setText(ticks);}});
}
static {System.loadLibrary("hello-jnicallback");
}
public native  String stringFromJNI();
public native void startTicks();
public native void StopTicks();

Android-NDK-hello-jniCallback相关推荐

  1. Android ndk 安装教程 以及环境变量配置

    现在android ndk 也是非常的方便 第一步 第二步搜索sdk 第三步 把界面切换到SDK Tools 界面 选中ndk  然后在点击Apply 下载即可 然后就是查看ndk 安装到那个目录下面 ...

  2. Android NDK开发之旅29 云服务器Ubuntu下搭建NDK环境,并编译FFmpeg

    ###前言 因为在Linux环境下编译FFmpeg生成库和头文件下比较方便,所以接下来主要操作在Linux环境下进行.但是对于Android NDK 开发新手来说,自己电脑配置Ubuntu Linux ...

  3. Android NDK开发之旅31 FFmpeg音频解码

    ###前言 #####基于Android NDK开发之旅30--FFmpeg视频播放这篇文章,我们已经学会视频解码基本过程.这篇文章就对音频解码进行分析. #####音频解码和视频解码的套路基本是一样 ...

  4. Android NDK基础样例

    Android NDK基础样例 NDK(Native Development Kit),用C/C++封装一些东西?好像就这么理解好了== 一.环境准备 这个好讨厌==!因为我环境都已经搭了很久了. 已 ...

  5. 基于 Android NDK 的学习之旅-----资源释放

    基于 Android NDK 的学习之旅-----资源释放 做上一个项目的时候因为与C引擎交互频繁,有时候会突然莫名其妙的的整个应用程序直接挂掉.因为我是学Java 开始的,所以对主动释放内存没多大概 ...

  6. android ndk platform,Android NDK Platform Build and Application

    摘要: Since the launch of Android NDK,the official guide of its building process and application under ...

  7. windows系统上安装与使用Android NDK

    转自http://www.cnblogs.com/luxiaofeng54/archive/2011/02/12/1952391.html 很早就听说了android的NDK应用,只是一直没有时间去研 ...

  8. 基于 Android NDK 的学习之旅----- C调用Java

    2019独角兽企业重金招聘Python工程师标准>>> 基于 Android NDK 的学习之旅----- C调用Java 许多成熟的C引擎要移植到Android 平台上使用 , 一 ...

  9. 怎么新建android.mk,Android NDK简单编写HelloWorld过程笔记(详细)

    Android NDK,坑啊,对于不会c的人来说更是坑啊,弄了一整天才把程序调出来,在网上找了各种资料,各种解决出现的bug,终于是能够运行了. 考虑了一下,还是做个目录吧. 1.创建一个项目 2.编 ...

  10. ugui 转轮_Unity3D研究院之Android NDK编译C/C++结合Unity实现本地数据共享(二十八)...

    开始本篇文章之前我先为大家简单的介绍一下Android NDK编程的原理, 我们知道Android开发使用JAVA语言来编程它的运行效率要比C/C++低很多,为了让JAVA语言可以调用 C/C++ 这 ...

最新文章

  1. 学java培训开发需要多少钱
  2. Id.exe和ld.exe: cannot open output file … : Permission denied问题。
  3. 5、kafka的操作
  4. 新书品读《三级网络技术预测试卷与考点解析》,欢迎拍砖、跟砖提建议。
  5. java的如何创建js_[Java教程]JS创建事件的三种方式(实例)
  6. 7-3 sdut-求两个整数之和(I)
  7. 传感器工作原理_荧光氧气传感器工作原理简介
  8. 透明加密tde_如何在SQL Server中配置透明数据加密(TDE)
  9. 如何保证集合是线程安全的? ConcurrentHashMap如何实现高效地线程安全?(转)
  10. 8.15 SNAIL:神经注意力元学习
  11. Leo2DNT(雷傲论坛转DiscuzNT)1.0转换程序发布
  12. 手机摄像头采集并推流_助力网上广交会—OBS直播推流软件简易教程
  13. 国内手机市场寒风持续,华为与OV竞争将更激烈
  14. <<和>>运算符的用法
  15. npm install安装报错 npm ERR! code Z_BUF_ERROR 问题解决
  16. 【完整的WebGIS教程】7.1 ArcGIS API for JS行政区划导航(上)
  17. 使用python异步框架aiohttp从NASA抓取火星图片
  18. Mysql查询历史SQL执行记录
  19. 2018-2019 20165208 网络对抗 Exp7 网络欺诈防范
  20. FastStone Capture安装包正版激活码使用说明

热门文章

  1. String案例 获取一个字符串在另一个字符串中出现的次数(两种方法)
  2. Swift之深入解析如何使用Xcode和LLDB v2修改UI元素
  3. Check failed: weights_.Size() == num_row_ (38997 vs. 383852) : Size of weights must equal to number.
  4. 信息学奥赛一本通(C++)在线评测系统——基础(一)C++语言——1079:计算分数加减表达式的值
  5. Java中集合(七)Collections 一个操作集合的工具类
  6. 解决安装ROS 时rosdep update 问题(time out)
  7. Deep-Learning-with-Python] 文本序列中的深度学习
  8. 【嵌入式】C语言高级编程-地址对齐(07)
  9. 【Linux】一步一步学Linux——chmod命令(110)
  10. python opencv轮廓提取_Python + Opencv2 实现轮廓提取,轮廓区域面积计算