JNI调用Java函数,主要是在JNI中使用反射调用Java中的函数。
1、Java代码:
package com.my.hawk.jni2; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.TextView; import static java.lang.String.format; public class MainActivity extends AppCompatActivity { TextView tv; // Used to load the 'native-lib' library on application startup. static { System.loadLibrary("native-lib"); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Example of a call to a native method tv = findViewById(R.id.sample_text); tv.setText(stringFromJNI()); nativeInitilize(); Button startBt = findViewById(R.id.button); startBt.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { nativeThreadStart(); } }); Button stopBt = findViewById(R.id.button2); stopBt.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { nativeThreadStop(); } }); } public void onNativeCb(int count) { Log.d("Native", "onNativeCb count=" + count); // TextView tv = findViewById(R.id.sample_text); // tv.setText(format("%s%d", stringFromJNI(), count)); tv.post(new Runnable() { @Override public void run() { tv.setText(format("%s%d", stringFromJNI(), count)); } }); } /** * A native method that is implemented by the 'native-lib' native library, * which is packaged with this application. */ public native String stringFromJNI(); public native void nativeInitilize(); public native void nativeThreadStart(); public native void nativeThreadStop(); }
2、JNI代码
#include <jni.h> #include <string> #include <sstream> #include <android/log.h> #include <unistd.h> JavaVM *gJavaVm; jobject gJaveObj; static volatile int gIsThreadExit = 0; #define LOG(...) __android_log_print(ANDROID_LOG_DEBUG, "Native", __VA_ARGS__) static const char *classPath = "com/my/hawk/jni2/MainActivity"; extern "C" JNIEXPORT jstring JNICALL Java_com_my_hawk_jni2_MainActivity_stringFromJNI( JNIEnv* env, jobject /* this */) { std::string hello = "Hello from C++"; return env->NewStringUTF(hello.c_str()); } extern "C" JNIEXPORT void JNICALL Java_com_my_hawk_jni2_MainActivity_nativeInitilize(JNIEnv *env, jobject thiz) { env->GetJavaVM(&gJavaVm); gJaveObj = env->NewGlobalRef(thiz); } static void* native_thread_exec(void *arg) { JNIEnv *env; gJavaVm->AttachCurrentThread(&env, nullptr); // jclass javaClass = env->FindClass(classPath); jclass javaClass = env->GetObjectClass(gJaveObj); if (javaClass == nullptr) { LOG("Fail to find javaClass"); return nullptr; } jmethodID javaCallback = env->GetMethodID(javaClass, "onNativeCb", "(I)V"); if (javaCallback == nullptr) { LOG("Fail to find method onNativeCb"); return nullptr; } LOG("native_thread_exec loop enter"); int count = 0; while (!gIsThreadExit) { env->CallVoidMethod(gJaveObj, javaCallback, count++); sleep(1); } gJavaVm->DestroyJavaVM(); LOG("native_thread_exec loop leave"); return nullptr; } extern "C" JNIEXPORT void JNICALL Java_com_my_hawk_jni2_MainActivity_nativeThreadStart(JNIEnv *env, jobject thiz) { gIsThreadExit = 0; pthread_t threadId; if (pthread_create(&threadId, nullptr, native_thread_exec, nullptr) != 0) { LOG("native_thread_start pthread_create fail!"); return; } LOG("native_thread_start success"); } extern "C" JNIEXPORT void JNICALL Java_com_my_hawk_jni2_MainActivity_nativeThreadStop(JNIEnv *env, jobject thiz) { gIsThreadExit = 1; LOG("native_thread_stop success"); }
其中的关键,获取方法,然后通过反射调用native_thread_exec
初始化的时候保存全局JVM和class对象 初始化的时候保存全局
env->GetJavaVM(&gJavaVm); gJaveObj = env->NewGlobalRef(thiz);
1、Android环境中,每个进程只能诞生一个JavaVM对象,被所有线程共享。在VM加载*.so程序库时,会先调用JNI_OnLoad()函数,在JNI_OnLoad()函数中会将JavaVM指针对象保存到c层JNI的全局变量中。
2、JNIEnv对象和线程是一一对应的关系;
3、Jvm和JNIEnv释放问题?JVM 中 Java Heap 的内存泄漏?JVM 内存中 native memory 的内存泄漏?
4、从操作系统角度看,JVM 在运行时和其它进程没有本质区别。在系统级别上,它们具有同样的调度机制,同样的内存分配方式,同样的内存格局。JVM 进程空间中,Java Heap 以外的内存空间称为 JVM 的 native memory。进程的很多资源都是存储在 JVM 的 native memory 中,例如载入的代码映像,线程的堆栈,线程的管理控制块,JVM 的静态数据、全局数据等等。也包括 JNI 程序中 native code 分配到的资源。
Local Reference 导致的内存泄漏?
参考:Android开发实践:JNI层线程回调Java函数示例 - 指针空间 - 博客园
JNI开发:JNI层新起的函数中(C回调函数中)调用JAVA层的接口_tingzhushaohua的博客-CSDN博客_jni 回调函数
jni java 函数指针_java native interface JNI 调用Java方法_我是XiaoYang呀的博客-CSDN博客
JNI数据传递
Android:JNI调用C++自定义类的详细方法_chaoqiangscu的博客-CSDN博客_jni调用c++类
Java代码与Jni层之间传递数组(byte[])_xiao慕r的博客-CSDN博客_jni传递数组
Android-JNI之数据类型转换_zhezi521的博客-CSDN博客_android jni 类型转换
android ndk 返回字符串,android ndk返回String(字符串)_天才娜娜ln的博客-CSDN博客
小心ReleaseByteArrayElements 中的参数问题_普通网友的博客-CSDN博客
java jni 手册_Java中JNI的使用详解第二篇:JNIEnv类型和jobject类型的解释_发条粽子的博客-CSDN博客
Android之OpenCv简单人脸识别功能(Bitmap)_路和远方的博客-CSDN博客_android opencv 人脸识别
android中通过JNI读取Bitmap文件,并调用opencv进行处理_一天到晚游泳的鱼啊鱼的博客-CSDN博客
JNI 通过形参String返回数据的方法_Cosmo_Wang1989的博客-CSDN博客_jni 形参返回字符串
简介Bitmap、YUV,NV21与Bitmap互转_XDK-Net的博客-CSDN博客_bitmap转nv21
bitmap 转换nv21_驱梦人的博客-CSDN博客_bitmap转nv21
Android开发实践:JNI函数签名生成器 - 行业资讯 - 肥雀云_南京肥雀信息技术有限公司
native和static native区别_飞鸟_的博客-CSDN博客_jni static
JNA
JNI便捷开发框架JNA框架之入门(一)_cy谭的博客-CSDN博客_jna
JNI便捷开发框架JNA框架之指针参数Pointer(二)_cy谭的博客-CSDN博客_jna pointer
JNI便捷开发框架JNA框架之引用传递ByReference(三)_cy谭的博客-CSDN博客
JNI便捷开发框架JNA框架之结构参数体传递(四)_cy谭的博客-CSDN博客_jna 结构体传参
JNA传递二维指针数组参数给C语言_Xeon_CC的博客-CSDN博客_jna传递数组给c
JNA 技术解密_ccfeng2008的博客-CSDN博客_jna原理
java高级用法之:JNA中的回调_flydean程序那些事的博客-CSDN博客_jna 回调函数
Jna及如何调试_nanshenjiang的博客-CSDN博客_jna测试
libffi浅析_ayu_ag的博客-CSDN博客_libffi
使用 libffi 实现 AOP_diaoju3333的博客-CSDN博客
【libffi】动态调用&定义C函数_Yaso_GG的博客-CSDN博客_libffi
android下使用JNA_10km的博客-CSDN博客_android jna
Ubuntu 12.04下制作JNA For Android_齐北的博客-CSDN博客
移动端视频进阶(三):OpenCV的集成及视频帧转cv::Mat的相关操作_木大白易的博客-CSDN博客
Android 相机 NV21 byte[] 和 JPEG byte[] 转 OpenCV 的 Mat_weixin_33973609的博客-CSDN博客
在IOS上YUV NV21格式的CVPixelBufferRef转opencv的RGB格式cv::Mat的方法_星辰辰大海的博客-CSDN博客