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函数示例 - 指针空间 - 博客园​​


​C++通过JNI层回调java函数 - 百度文库​

​Android NDK开发(一) - 简书​



JNI数据传递

​JNIEnv*的常用函数详解​

​NDK 开发之 Bitmap 的使用-技术圈​

​JNI层向Java层传递bitmap | 码农家园​

​JNI String类型 - 知乎​

​JNI层向Java层传递bitmap | 码农家园​

​计算Java函数的签名 |​

​Android开发实践:JNI函数签名生成器 - 行业资讯 - 肥雀云_南京肥雀信息技术有限公司​



JNA

​jna编程学习 - 走看看​

​深入浅出JNA​