소켓에서 데이터를 받아 Java에서 입력 매개 변수 인 ByteArray에 다시 쓸 수있는 네이티브 메서드를 작성하려고합니다. ByteArray를 Java 측에 할당하고 네이티브 메소드에 전달하기 때문에 GetPrimitiveArrayCritical()을 사용하여이 ByteArray의 포인터를 가져와야합니다.안드로이드 JNI 네이티브 C++ 코드 GetPrimitiveArrayCritical() 문제
는 그러나, 나는 여전히 스레드에서 실행하려면이 절차가 필요합니다, 그래서 구조체의 jbyteArray 변수가이 입력 된 ByteArray를 기억 socket_loop_native_data라고 사용하고 입력 매개 변수로이 구조체에 새로운 스레드를 시작하기는 pthread_create()를 사용 .
마지막으로, 스레드의 본체 코드에서, 나는 이전이 ByteArray의 포인터를 얻을 수 GetPrimitiveArrayCritical에()를 사용하지만,
오류 로그
은 ... 실패 :14:09:32.350 Warning dalvikvm 2780 JNI WARNING: 0x4077ab48 is not a valid JNI reference
14:09:32.350 Warning dalvikvm 2780 in Ldalvik/system/NativeStart;.run()V (GetPrimitiveArrayCritical)
내 네이티브 코드의 조각
struct socket_loop_native_data {
pthread_mutex_t thread_mutex;
pthread_t thread;
struct pollfd *pollData;
JavaVM *vm;
int envVer;
jobject me;
jbyteArray javaBuffer;
int bufferSize;
jbyte *nativeBuffer;
char *beginOfBuffer;
char *endOfBuffer;
int decodedDataSize;
bool running;
};
typedef socket_loop_native_data native_data_t;
static jfieldID field_mNativeDataSocket;
static inline native_data_t *get_native_data(JNIEnv *env, jobject object) {
return (native_data_t *)(env->GetIntField(object, field_mNativeDataSocket));
}
native_data_t *get_SocketLoop_native_data(JNIEnv *env, jobject object) {
return get_native_data(env, object);
}
JNIEXPORT void JNICALL Java_android_classInitNativeSocket(JNIEnv* env, jclass clazz) {
field_mNativeDataSocket = env->GetFieldID(clazz, "mNativeDataSocket", "I");
}
JNIEXPORT void JNICALL Java_android_initializeNativeDataNativeSocket(JNIEnv* env, jobject object) {
native_data_t *nat = (native_data_t *)calloc(1, sizeof(native_data_t));
if (NULL == nat) {
LOGD("%s: out of memory!", __FUNCTION__);
return;
}
memset(nat, 0, sizeof(native_data_t));
pthread_mutex_init(&(nat->thread_mutex), NULL);
env->SetIntField(object, field_mNativeDataSocket, (jint)nat);
}
JNIEXPORT jboolean JNICALL Java_android_startSocketLoopNative(JNIEnv *env, jobject object, jint sock, jbyteArray buffer, jint size) {
jboolean result = JNI_FALSE;
socket_loop_native_data *nat = get_native_data(env, object);
pthread_mutex_lock(&(nat->thread_mutex));
nat->running = false;
if (nat->pollData) {
LOGD("trying to start SocketLoop a second time!");
pthread_mutex_unlock(&(nat->thread_mutex));
return JNI_FALSE;
}
nat->pollData = (struct pollfd *)malloc(sizeof(struct pollfd));
if (!nat->pollData) {
LOGD("out of memory error starting SocketLoop!");
goto done;
}
memset(nat->pollData, 0, sizeof(struct pollfd));
nat->pollData[0].fd = sock;
nat->pollData[0].events = POLLIN;
env->GetJavaVM(&(nat->vm));
nat->envVer = env->GetVersion();
nat->me = env->NewGlobalRef(object);
nat->javaBuffer = buffer;
nat->bufferSize = (int)size;
nat->decodedDataSize = 0;
pthread_create(&(nat->thread), NULL, socketLoopMain, nat);
result = JNI_TRUE;
done:
if (JNI_FALSE == result) {
if (nat->me) env->DeleteGlobalRef(nat->me);
nat->me = NULL;
if (nat->pollData) free(nat->pollData);
nat->pollData = NULL;
}
pthread_mutex_unlock(&(nat->thread_mutex));
return result;
}
static void *socketLoopMain(void *ptr) {
native_data_t *nat = (native_data_t *)ptr;
JNIEnv *env;
JavaVMAttachArgs args;
char name[] = "SocketLoop";
args.version = nat->envVer;
args.name = name;
args.group = NULL;
nat->vm->AttachCurrentThread(&env, &args);
...
nat->nativeBuffer = (jbyte *)(env->GetPrimitiveArrayCritical((nat->javaBuffer), NULL));
nat->beginOfBuffer = (char *)(&(nat->nativeBuffer[0]));
nat->endOfBuffer = (char *)(&(nat->nativeBuffer[0])) + (nat->bufferSize);
...
}
VM을 같은 실행 후 문
,617을 중단하다nat->nativeBuffer = (jbyte *)(env->GetPrimitiveArrayCritical((nat->javaBuffer), NULL));
이렇게 ... 입력 ByteArray를 기억하고 다른 장소에서 GetPrimitiveArrayCritical()을 호출하기 위해 jbyteArray 변수를 사용할 수 없거나 사용할 수 없다는 의미입니까?
아니면, 내가 잊어 버린 것은 무엇입니까 ???
모든 의견을 크게 높이세요 !!!
해결 : NewGlobalRef()를 사용해야합니다. –