Android JNI 回调示例,展示了本地 C++ 代码如何通过 JNI 回调 Java 层接口。

MainActivity.kt
Kotlin
package com.demo.learn2
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.util.Log
import androidx.activity.ComponentActivity
class MainActivity : ComponentActivity() {
// 用于存储本地对象的指针
private var nativeWorkerPtr: Long = 0 // 初始化为 0
// 加载本地库
init {
System.loadLibrary("native_code")
}
// 本地方法声明
external fun startNativeThread(callback: NativeCallback)
external fun stopNativeThread()
// 回调接口
interface NativeCallback {
fun onProgressUpdate(progress: Int)
fun onMessageReceived(message: String)
fun onError(errorCode: Int, errorMessage: String)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 创建回调实现
val callback = object : NativeCallback {
override fun onProgressUpdate(progress: Int) {
Log.d("JNICallback", "Progress updated: $progress%")
}
override fun onMessageReceived(message: String) {
Log.d("JNICallback", "Message received: $message")
}
override fun onError(errorCode: Int, errorMessage: String) {
Log.e("JNICallback", "Error $errorCode: $errorMessage")
}
}
// 启动本地线程
startNativeThread(callback)
// 10秒后停止线程(示例)
Handler(Looper.getMainLooper()).postDelayed({
stopNativeThread()
}, 10000)
}
}
CMakeLists.txt
cpp
cmake_minimum_required(VERSION 3.4.1)
set(CMAKE_CXX_STANDARD 11) # 启用C++11支持
project("native_code") #定义项目名称为 "native_code"
add_library(
native_code
SHARED
native_code.cpp
native_code.h
)
#设置头文件搜索路径
target_include_directories(
native_code # 目标库名称
PRIVATE # 表示这些路径仅用于构建该库
${CMAKE_SOURCE_DIR} # CMake 变量,表示项目根目录
)
find_library(
log-lib
log
)
target_link_libraries(
native_code
android # 链接 Android NDK 平台库
${log-lib}
)
native_code.h
cpp
#ifndef LEARN2_NATIVE_CODE_H
#define LEARN2_NATIVE_CODE_H
#include <jni.h>
#include <string>
#include <thread>
#include <atomic>
class NativeWorker {
public:
NativeWorker(JNIEnv* env, jobject callback);
~NativeWorker();
void start();
void stop();
bool isRunning() const;
private:
void run();
JNIEnv* getJNIEnv(bool* attached);
void detachJNIEnv(bool attached);
JavaVM* jvm;
jobject javaCallbackRef;
jmethodID onProgressUpdateMethod;
jmethodID onMessageReceivedMethod;
jmethodID onErrorMethod;
std::thread workerThread;
std::atomic<bool> running;
};
#endif //LEARN2_NATIVE_CODE_H
NativeWorker 类定义
1. 公共接口
-
构造函数:接收 JNI 环境和 Java 回调对象
-
析构函数:负责资源清理
-
start():启动工作线程
-
stop():停止工作线程
-
isRunning():检查线程是否在运行
2. 私有成员
2.1 核心方法
-
run():工作线程的主逻辑
-
getJNIEnv():获取当前线程的 JNI 环境
-
detachJNIEnv():从当前线程分离 JVM
2.2 JNI 相关成员
-
jvm:保存 JavaVM 引用,用于后续获取 JNIEnv
-
javaCallbackRef:Java 回调对象的全局引用
-
onXXXMethod:三个 Java 回调方法的 ID
2.3 线程控制成员
-
workerThread:工作线程对象
-
running:原子布尔标志,用于线程安全地控制线程运行状态
3.关键设计要点
3.1 JNI 环境管理
-
JavaVM 保存:在构造函数中保存 JavaVM,用于后续在任何线程获取 JNIEnv
-
全局引用:将 Java 回调对象转换为全局引用,防止被垃圾回收
-
方法 ID 缓存:提前获取方法 ID 提升性能
3.2 线程安全设计
-
原子标志 :使用
std::atomic<bool>
确保running
标志的线程安全访问 -
线程生命周期 :通过
start()
/stop()
明确控制线程生命周期 -
资源清理:析构函数确保线程停止和资源释放
3.3 跨线程回调机制
-
全局引用:允许在不同线程回调 Java 方法
-
JNIEnv 获取 :
getJNIEnv()
处理线程附加/分离
4. 典型使用场景
cpp
// JNI 函数中创建 worker
NativeWorker* worker = new NativeWorker(env, callback);
worker->start();
// ...
worker->stop();
delete worker;
native_code.cpp
cpp
#include "native_code.h"
#include <android/log.h>
#define LOG_TAG "NativeCode"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
NativeWorker::NativeWorker(JNIEnv* env, jobject callback) : running(false) {
// 保存JavaVM引用
env->GetJavaVM(&jvm);
// 创建全局引用,防止被垃圾回收
javaCallbackRef = env->NewGlobalRef(callback);
// 获取回调方法ID
jclass callbackClass = env->GetObjectClass(callback);
onProgressUpdateMethod = env->GetMethodID(callbackClass, "onProgressUpdate", "(I)V");
onMessageReceivedMethod = env->GetMethodID(callbackClass, "onMessageReceived", "(Ljava/lang/String;)V");
onErrorMethod = env->GetMethodID(callbackClass, "onError", "(ILjava/lang/String;)V");
if (!onProgressUpdateMethod || !onMessageReceivedMethod || !onErrorMethod) {
LOGE("Failed to get method IDs");
}
}
NativeWorker::~NativeWorker() {
stop();
bool attached = false;
JNIEnv* env = getJNIEnv(&attached);
if (env) {
env->DeleteGlobalRef(javaCallbackRef);
}
detachJNIEnv(attached);
}
void NativeWorker::start() {
if (running) return;
running = true;
workerThread = std::thread(&NativeWorker::run, this);
}
void NativeWorker::stop() {
if (!running) return;
running = false;
if (workerThread.joinable()) {
workerThread.join();
}
}
bool NativeWorker::isRunning() const {
return running;
}
//获取当前线程的 JNI 环境,必要时附加到 JVM
JNIEnv* NativeWorker::getJNIEnv(bool* attached) {
*attached = false;
JNIEnv* env = nullptr;
// 获取当前线程的JNIEnv
jint status = jvm->GetEnv((void**)&env, JNI_VERSION_1_6);
if (status == JNI_EDETACHED) {
// 如果当前线程未附加到JVM,附加它
if (jvm->AttachCurrentThread(&env, nullptr) == JNI_OK) {
*attached = true;
} else {
LOGE("Failed to attach thread to JVM");
return nullptr;
}
} else if (status != JNI_OK) {
LOGE("Failed to get JNIEnv, status: %d", status);
return nullptr;
}
return env;
}
//如果需要,从当前线程分离 JVM
void NativeWorker::detachJNIEnv(bool attached) {
if (attached) {
jvm->DetachCurrentThread();
}
}
void NativeWorker::run() {
int progress = 0;
while (running && progress < 100) {
// 模拟工作
std::this_thread::sleep_for(std::chrono::milliseconds(200));
progress += 10;
bool attached = false;
JNIEnv* env = getJNIEnv(&attached);
if (!env) {
LOGE("Failed to get JNIEnv in worker thread");
continue;
}
// 回调进度更新
env->CallVoidMethod(javaCallbackRef, onProgressUpdateMethod, progress);
// 检查是否有异常
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
env->ExceptionClear();
LOGE("Exception occurred during callback");
}
// 每隔几次发送消息
if (progress % 20 == 0) {
jstring message = env->NewStringUTF("Progress milestone reached");
env->CallVoidMethod(javaCallbackRef, onMessageReceivedMethod, message);
env->DeleteLocalRef(message);
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
env->ExceptionClear();
LOGE("Exception occurred during message callback");
}
}
detachJNIEnv(attached);
}
// 工作完成或停止
bool attached = false;
JNIEnv* env = getJNIEnv(&attached);
if (env) {
if (progress >= 100) {
jstring message = env->NewStringUTF("Work completed");
env->CallVoidMethod(javaCallbackRef, onMessageReceivedMethod, message);
env->DeleteLocalRef(message);
} else {
jstring message = env->NewStringUTF("Work stopped");
env->CallVoidMethod(javaCallbackRef, onMessageReceivedMethod, message);
env->DeleteLocalRef(message);
}
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
env->ExceptionClear();
}
detachJNIEnv(attached);
}
}
// JNI函数实现
extern "C" {
JNIEXPORT void JNICALL
Java_com_demo_learn2_MainActivity_startNativeThread(JNIEnv* env, jobject thiz, jobject callback) {
// 创建并启动worker
NativeWorker* worker = new NativeWorker(env, callback);
worker->start();
// 存储worker指针到Java对象(简化示例,实际应更安全地处理)
jclass clazz = env->GetObjectClass(thiz);
jfieldID fieldId = env->GetFieldID(clazz, "nativeWorkerPtr", "J");
if (fieldId) {
env->SetLongField(thiz, fieldId, reinterpret_cast<jlong>(worker));
} else {
LOGE("Failed to find nativeWorkerPtr field");
}
}
JNIEXPORT void JNICALL
Java_com_demo_learn2_MainActivity_stopNativeThread(JNIEnv* env, jobject thiz) {
// 获取worker指针
jclass clazz = env->GetObjectClass(thiz);
jfieldID fieldId = env->GetFieldID(clazz, "nativeWorkerPtr", "J");
if (!fieldId) {
LOGE("Failed to find nativeWorkerPtr field");
return;
}
//停止并删除对象,清除指针
jlong ptr = env->GetLongField(thiz, fieldId);
NativeWorker* worker = reinterpret_cast<NativeWorker*>(ptr);
if (worker) {
worker->stop();
delete worker;
env->SetLongField(thiz, fieldId, 0L);
}
}
}
NativeWorker 类构造函数
cpp
NativeWorker::NativeWorker(JNIEnv* env, jobject callback) : running(false) {
// 保存JavaVM引用
env->GetJavaVM(&jvm);
// 创建全局引用,防止被垃圾回收
javaCallbackRef = env->NewGlobalRef(callback);
// 获取回调方法ID
jclass callbackClass = env->GetObjectClass(callback);
onProgressUpdateMethod = env->GetMethodID(callbackClass, "onProgressUpdate", "(I)V");
onMessageReceivedMethod = env->GetMethodID(callbackClass, "onMessageReceived", "(Ljava/lang/String;)V");
onErrorMethod = env->GetMethodID(callbackClass, "onError", "(ILjava/lang/String;)V");
}
-
构造函数接收 JNI 环境和 Java 回调对象
-
保存 JavaVM 引用(用于后续获取 JNIEnv)
-
创建回调对象的全局引用(防止被垃圾回收)
-
获取回调方法的 ID(用于后续调用)
NativeWorker 类析构函数
cpp
NativeWorker::~NativeWorker() {
stop();
bool attached = false;
JNIEnv* env = getJNIEnv(&attached);
if (env) {
env->DeleteGlobalRef(javaCallbackRef);
}
detachJNIEnv(attached);
}
-
停止工作线程
-
获取 JNI 环境
-
删除全局引用
-
如果需要,从当前线程分离 JVM
工作线程主逻辑
cpp
void NativeWorker::run() {
int progress = 0;
while (running && progress < 100) {
std::this_thread::sleep_for(std::chrono::milliseconds(200));
progress += 10;
bool attached = false;
JNIEnv* env = getJNIEnv(&attached);
if (!env) continue;
// 回调进度更新
env->CallVoidMethod(javaCallbackRef, onProgressUpdateMethod, progress);
// 检查异常
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
env->ExceptionClear();
LOGE("Exception occurred during callback");
}
// 每隔20%发送消息
if (progress % 20 == 0) {
jstring message = env->NewStringUTF("Progress milestone reached");
env->CallVoidMethod(javaCallbackRef, onMessageReceivedMethod, message);
env->DeleteLocalRef(message);
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
env->ExceptionClear();
LOGE("Exception occurred during message callback");
}
}
detachJNIEnv(attached);
}
// 工作完成或停止后的处理
bool attached = false;
JNIEnv* env = getJNIEnv(&attached);
if (env) {
jstring message = env->NewStringUTF(progress >= 100 ? "Work completed" : "Work stopped");
env->CallVoidMethod(javaCallbackRef, onMessageReceivedMethod, message);
env->DeleteLocalRef(message);
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
env->ExceptionClear();
}
detachJNIEnv(attached);
}
}
-
模拟工作进度(每200毫秒增加10%)
-
定期回调 Java 方法更新进度
-
每20%发送一个里程碑消息
-
处理完成后发送最终消息
关键点总结
-
线程管理 :使用 C++11 的
std::thread
创建本地线程 -
JNI 环境处理:正确处理线程附加/分离 JVM
-
Java 回调:通过全局引用和方法 ID 安全回调 Java 方法
-
异常处理:检查并清除 JNI 调用可能产生的异常
-
内存管理:正确管理全局引用和本地对象
-
线程安全 :使用
running
标志控制线程生命周期