Android JNI实现线程内部调用JAVA方法

发布于:2024-05-10 ⋅ 阅读:(23) ⋅ 点赞:(0)
  1. JNILib.java
class JNILib() {
    external fun start(callBack: DataCallBack):Int
    interface DataCallBack{
        fun onData(type:Int,data:ByteArray)
    }
}
  1. jni.cpp
static MessageUtil messageUtil;
// 全局变量,表示 Java 虚拟机
JavaVM* g_vm = nullptr;
// 用于保存回调对象的全局引用
jobject callBack = nullptr;
// 在 JNI 库加载时保存 Java 虚拟机的引用
extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
    g_vm = vm;
    return JNI_VERSION_1_6;
}
extern "C"
JNIEXPORT jint JNICALL
Java_com_test_jni_JNILib_start(JNIEnv *env, jobject thiz, jobject call_back) {
    // 创建回调对象的全局引用
    callBack = env->NewGlobalRef(call_back);
    // 获取回调对象的类
    jclass callbackClass = env->GetObjectClass(callBack);
     // 启动线程并传递 Java 虚拟机、JNIEnv、回调对象及其类
    messageUtil.startThread(g_vm,env,callBack,callbackClass);
    return 0;
}
  1. message_.h
#include <jni.h>
#include <queue>
#include <pthread.h>
#include "logcat.h"
#include <string>

struct Message {
    int type;
    const char* data;
    size_t length;
};

class MessageUtil{
public:
    std::queue<Message> dataQueue;
    pthread_mutex_t mutex_;
    pthread_cond_t condition_;
    bool isThreadRunning = false;
    pthread_t msgThread;
    // 线程函数
    static void* threadFunction(void* arg);

    // 开始线程
    void startThread(JavaVM* gVm,JNIEnv* env,jobject callback,jclass callbackClass);
    // 停止线程
    void stopThread();
    // 添加数据
    void addMessage(Message msg);

    jobject callback;
    JavaVM* g_vm;
    jmethodID dataMethod;
};
  1. message.cpp
JNIEnv* AttachCurrentThreadIfNeeded(JavaVM* g_vm) {
    LogUtil::info(Message_TAG, "AttachCurrentThreadIfNeeded");
    // 声明 JNIEnv 指针
    JNIEnv* env;
    // 获取当前线程的 JNIEnv
    jint result = g_vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6);
    if (result == JNI_EDETACHED) {
        g_vm->AttachCurrentThread(&env, nullptr);
    }
    // 返回 JNIEnv 指针
    return env;
}
// 线程函数
void* MessageUtil::threadFunction(void* arg) {
	// 将参数转换为 MessageUtil 对象指针
    MessageUtil* messageUtil = static_cast<MessageUtil*>(arg);
    // 在当前线程附加到 Java 虚拟机
    JNIEnv* env = AttachCurrentThreadIfNeeded(messageUtil ->g_vm);
    // 线程主循环
    while (messageUtil ->isThreadRunning) {
    	// 加锁互斥量
        pthread_mutex_lock(&messageUtil ->mutex_);
		// 当数据队列为空时,线程等待条件变量
        while (messageUtil ->dataQueue.empty()) {
            pthread_cond_wait(&messageUtil ->condition_, &messageUtil ->mutex_);
        }
        // 检查线程是否需要退出
        if (!messageUtil ->isThreadRunning) {
            pthread_mutex_unlock(&messageUtil ->mutex_);
            break;
        }
        // 从队列中获取数据
        if (!messageUtil ->dataQueue.empty()){
//            LogUtil::info(Message_TAG,"成功发送数据");
            Message message = messageUtil ->dataQueue.front();
            messageUtil ->dataQueue.pop();
            // 创建字节数组并复制数据
            jbyteArray retData = env->NewByteArray(message.length);
            env->SetByteArrayRegion(retData, 0, message.length, reinterpret_cast<const jbyte*>(message.data));
            // 调用 Java 中的回调方法
            env->CallVoidMethod( messageUtil ->callback, messageUtil ->dataMethod,message.type, retData);
        }
        // 解锁互斥量
        pthread_mutex_unlock(&messageUtil ->mutex_);
    }
    // 从 Java 虚拟机中分离当前线程
    messageUtil ->g_vm->DetachCurrentThread();
    // 删除全局引用的回调对象
    env->DeleteGlobalRef(messageUtil ->callback);
    // 退出线程
    pthread_exit(NULL);
}


// 开始线程
void MessageUtil::startThread(JavaVM* gVm,JNIEnv* env,jobject callback,jclass callbackClass) {
	// 保存 Java 虚拟机、回调对象及其类
    MessageUtil::callback = callback;
    MessageUtil::g_vm = gVm;
    // 获取回调方法的 ID
    dataMethod = env->GetMethodID(callbackClass, "onData", "(I[B)V");
    isThreadRunning = true;
    // 创建线程
    pthread_create(&msgThread, NULL, &threadFunction, this);
}

// 停止线程
void MessageUtil::stopThread() {
    isThreadRunning = false;
    // 等待线程退出
    pthread_join(msgThread, NULL);
}

void MessageUtil::addMessage(Message message) {
	// 加锁互斥量
    pthread_mutex_lock(&mutex_);
    // 将消息添加到队列中
    dataQueue.push(message);
    if (dataQueue.size() > 20){
        LogUtil::info(Message_TAG,("dataQueue size = "+std::to_string(dataQueue.size())).c_str());
        dataQueue.pop();
    }
    // 发送条件信号
    pthread_cond_signal(&condition_);
    // 解锁互斥量
    pthread_mutex_unlock(&mutex_);
}