- JNILib.java
class JNILib() {
external fun start(callBack: DataCallBack):Int
interface DataCallBack{
fun onData(type:Int,data:ByteArray)
}
}
- jni.cpp
static MessageUtil messageUtil;
JavaVM* g_vm = nullptr;
jobject callBack = nullptr;
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);
messageUtil.startThread(g_vm,env,callBack,callbackClass);
return 0;
}
- 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;
};
- message.cpp
JNIEnv* AttachCurrentThreadIfNeeded(JavaVM* g_vm) {
LogUtil::info(Message_TAG, "AttachCurrentThreadIfNeeded");
JNIEnv* env;
jint result = g_vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6);
if (result == JNI_EDETACHED) {
g_vm->AttachCurrentThread(&env, nullptr);
}
return env;
}
void* MessageUtil::threadFunction(void* arg) {
MessageUtil* messageUtil = static_cast<MessageUtil*>(arg);
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()){
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));
env->CallVoidMethod( messageUtil ->callback, messageUtil ->dataMethod,message.type, retData);
}
pthread_mutex_unlock(&messageUtil ->mutex_);
}
messageUtil ->g_vm->DetachCurrentThread();
env->DeleteGlobalRef(messageUtil ->callback);
pthread_exit(NULL);
}
void MessageUtil::startThread(JavaVM* gVm,JNIEnv* env,jobject callback,jclass callbackClass) {
MessageUtil::callback = callback;
MessageUtil::g_vm = gVm;
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_);
}