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_) ;
}