나는 이것이 오래되었다는 것을 알고 있지만, 사람들은 아직도 그것을 검색에서 찾는다.
을 프로젝트 JNI 디렉토리
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_ALLOW_UNDEFINED_SYMBOLS=false
LOCAL_MODULE := testjni
LOCAL_SRC_FILES := testjni.c
LOCAL_LDLIBS := -llog -ljnigraphics
include $(BUILD_SHARED_LIBRARY)
응용 프로그램 만들기에 Android.mk를 작성 : 여기
자바에서 C 코드를 호출하고, JNI C 코드에서 자바 코드를 다시 호출하는 방법, 전체 솔루션입니다. MK 프로젝트의 JNI의 디렉토리에
APP_ABI := armeabi-v7a
APP_PLATFORM := android-8
프로젝트 JNI 디렉토리에 testjni.c 만들기
JNI 폴더 실행 NDK 빌드에서
#include <jni.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <pthread.h>
#include <android/log.h>
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,"TAG",__VA_ARGS__)
JavaVM *myVm;
static void *android_gui = NULL;
jint JNI_OnLoad(JavaVM *vm, void *reserved)
{
// Keep a reference on the Java VM.
myVm = vm;
LOGD("JNI interface loaded.");
return JNI_VERSION_1_2;
}
void jni_setDataEnv(JNIEnv *p_env, int width, int height)
{
if (android_gui == NULL)
return;
jclass cls = (*p_env)->GetObjectClass (p_env, android_gui);
jmethodID methodId = (*p_env)->GetMethodID (p_env, cls, "setData", "(II)V");
//add or delete II's depinding your number or variable passsed
(*p_env)->CallVoidMethod (p_env, android_gui, methodId, width, height);
(*p_env)->DeleteLocalRef(p_env, cls);
}
void jni_setData(int width, int height)
{
JNIEnv *p_env;
(*myVm)->AttachCurrentThread (myVm, &p_env, NULL);
jni_setDataEnv(p_env, width, height);
int check = (*myVm)->GetEnv(myVm, (void *) &p_env, JNI_VERSION_1_2);
LOGD(" Detach destructor = %d", check);
if (check != JNI_EDETACHED)
{
int detach = (*myVm)->DetachCurrentThread (myVm);
LOGD("Detach result ==: %d", detach);
}
}
//change this to your package
JNIEXPORT void JNICALL Java_com_example_test_LibTest_initM(JNIEnv *env, jobject thiz, jobject gui)
{
android_gui = (*env)->NewGlobalRef(env, gui);
}
//when you need , in your c code call jni_setData(100.200) and
//MainActivity method , setData() will receive this values
void *call_from_thread()
{
jni_setData(1,2);
return NULL;
}
JNIEXPORT void JNICALL Java_com_example_test_LibTest_test(JNIEnv *env, jobject thiz)
{
pthread_t t;
//do hard work in a thread
pthread_create(&t, NULL, call_from_thread, NULL);
}
만들기
libtest.so 라이브러리를 컴파일 : MyInterface.java 당신의 자바 안드로이드 프로젝트 SRC에
package com.example.test;
public interface MyInterface
{
void setData(int width, int height);
}
만들기 LibTest.java // 데이터를 전송하는 데 사용 자바에서 C 코드에
package com.example.test;
public class LibTest
{
static
{
System.loadLibrary("testjni");
}
private static LibTest sInstance;
public static LibTest getInstance()
{
synchronized (LibTest.class)
{
if (sInstance == null)
{
/* First call */
sInstance = new LibTest();
}
}
return sInstance;
}
public native void initM(MyInterface myinterface);
public native void test();
}
package com.example.test;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
public class MainActivity extends Activity implements MyInterface
{
int mHeight;
int mWidth;
LibTest libtest;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
libtest = LibTest.getInstance();
libtest.initM(MainActivity.this);
//tell jni to send us some data
//we receive data in 'setData(int width, int height)' method
libtest.test();
}
@Override
public void setData(int width, int height)
{
/// Here you receive data from C code
//We can store the values C send to Java so we use latter
mHeight = height;
mWidth = width;
Log.d("TAG" ,"GOT SOME DATA FROM C CODE" + mHeight + " " + mWidth);
}
}
MainActivity.java 만들기
주어진 함수의 반환 후에 유효한 전역 변수에 복사 한 값을 믿을 수는 없을 것 같습니다. 내 자신의 비슷한 상황에서, 또한 안드로이드에서 포인터를 전역 변수로 저장하는 것을 멈추고 JVM이 내 모듈에 호출 할 때 문제를 해결했습니다. – mah
VM 포인터를 캐시하는 것은 괜찮지 만 변경하지는 말아야합니다. 그러나 위에서와 같이 다중 스레드 호환성을 보장하려면'JNIEnv'를 얻어야합니다. – Samhain
한 스레드 응용 프로그램을 다루는 경우 JNIEnv 전역 초기화를 한 번 수행 한 다음 jni 메서드를 여러 번 호출 (한 스레드에서) 할 수 있습니다. – Lighter