JNI调用Java方法

Posted 胡刚2021

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JNI调用Java方法相关的知识,希望对你有一定的参考价值。

推荐阅读:JNI/NDK入门指南之JNI多线程回调Java方法

gitee代码链接

1.JNI 调用 Java 无参数无返回值的方法

public native void native_call_java_callBack_method();
public void callBack()
    Toast.makeText(this, "调用java无参无返回值方法", Toast.LENGTH_LONG).show();

extern "C"
JNIEXPORT void JNICALL
Java_com_example_myjnicalljava_MainActivity_native_1call_1java_1callBack_1method(JNIEnv *env,
                                                                                 jobject thiz) 
    // TODO: implement native_call_java_callBack_method()
    LOGI("=========== native_call_java_callBack_method ===========");
    jclass jcl = env->GetObjectClass(thiz);
    jmethodID mid = env->GetMethodID(jcl, "callBack", "()V");
    env->CallVoidMethod(thiz, mid);

2.JNI 调用 Java 整型参数无返回值方法

public native void native_call_java_integer_signature_callBack_method();
public void callBack(int num)
    Toast.makeText(this, "调用java有参无返回值方法, 返回整型参数:"+num, Toast.LENGTH_LONG).show();

extern "C"
JNIEXPORT void JNICALL
Java_com_example_myjnicalljava_MainActivity_native_1call_1java_1integer_1signature_1callBack_1method(
        JNIEnv *env, jobject thiz) 
    // TODO: implement native_call_java_integer_signature_callBack_method()
    LOGI("=========== native_call_java_integer_signature_callBack_method ===========");
    jclass jcl = env->GetObjectClass(thiz);
    jmethodID mid = env->GetMethodID(jcl, "callBack", "(I)V");
    env->CallVoidMethod(thiz, mid, 145);

3.JNI 调用 Java 整型数组参数无返回值方法

public native void native_call_java_integerArray_signature_callBack_method();
public void callBack(int[] arr)
    Toast.makeText(this, "调用java有参无返回值方法, 返回整型数组参数:"+arr[0]+","+arr[1]+","+arr[2], Toast.LENGTH_LONG).show();

extern "C"
JNIEXPORT void JNICALL
Java_com_example_myjnicalljava_MainActivity_native_1call_1java_1integerArray_1signature_1callBack_1method(
        JNIEnv *env, jobject thiz) 
    // TODO: implement native_call_java_integerArray_signature_callBack_method()
    LOGI("=========== native_call_java_integer_signature_callBack_method ===========");
    jclass jcl = env->GetObjectClass(thiz);
    jmethodID mid = env->GetMethodID(jcl, "callBack", "([I)V");

    jintArray newArr = env->NewIntArray(3);
    int32_t a[3] = -145,82,74;
    env->SetIntArrayRegion(newArr, 0, 3, a);
    env->CallVoidMethod(thiz, mid, newArr);
    jint* pnewArr = env->GetIntArrayElements(newArr, 0);
    env->ReleaseIntArrayElements(newArr, pnewArr, 0);

4.JNI 调用 Java 字符串型参数无返回值方法

public native void native_call_java_string_signature_callBack_method();
public void callBack(String str)
    Toast.makeText(this, "调用java有参无返回值方法, 返回字符串型参数:"+str, Toast.LENGTH_LONG).show();

extern "C"
JNIEXPORT void JNICALL
Java_com_example_myjnicalljava_MainActivity_native_1call_1java_1string_1signature_1callBack_1method(
        JNIEnv *env, jobject thiz) 
    // TODO: implement native_call_java_string_signature_callBack_method()
    LOGI("=========== native_call_java_string_signature_callBack_method ===========");
    jclass jcl = env->GetObjectClass(thiz);
    // 注意括号里面有分号
    jmethodID mid = env->GetMethodID(jcl, "callBack", "(Ljava/lang/String;)V");
    std::string hello = "Hello from JNI";
    env->CallVoidMethod(thiz, mid, env->NewStringUTF(hello.c_str()));

5.JNI 在子线程生成整型数组并回调 Java 整型数组参数无返回值方法

public native void native_thread_call_java_integerArray_signature_callBack_method();
public String str = "";
public void callBack(int[] arr, int length)
    Log.e(TAG, "callBack: length = "+length);

    for (int n : arr)
        str+=", ";
        str+=n;
    
    runOnUiThread(
        new Runnable() 
            @Override
            public void run() 
                Toast.makeText(getApplicationContext(), "JNI在子线程生成整型数组并回调Java整型数组参数无返回值方法,JNI生成的整型数组为:"+str, Toast.LENGTH_LONG).show();
            
        
    );

JavaVM* mVm = NULL;
jobject mObj = NULL;

void* native_thread_exec(void* args)
    LOGI("=========== native_thread_exec ===========");
    JNIEnv *env;
    //从全局的JavaVM中获取到环境变量
    mVm->AttachCurrentThread(&env,NULL);
    jclass clazz = env->GetObjectClass(mObj);
    jmethodID postID = env->GetMethodID(clazz,"callBack","([II)V");
    jintArray newArr = env->NewIntArray(5);
    int32_t a[5] = 415,789,654,-874,-842;
    env->SetIntArrayRegion(newArr, 0, 5, a);
    env->CallVoidMethod(mObj, postID, newArr, 5);
    
    jint* pnewArr = env->GetIntArrayElements(newArr, 0);
    env->ReleaseIntArrayElements(newArr, pnewArr, 0);
    mVm->DetachCurrentThread();
    pthread_exit(NULL);

extern "C"
JNIEXPORT void JNICALL
Java_com_example_myjnicalljava_MainActivity_native_1thread_1call_1java_1integerArray_1signature_1callBack_1method(
        JNIEnv *env, jobject thiz) 
    // TODO: implement native_thread_call_java_integerArray_signature_callBack_method()
    LOGI("=========== native_thread_call_java_integerArray_signature_callBack_method ===========");
    if (!mObj) 
        LOGI("=========== !mObj ===========");
        mObj = env->NewGlobalRef(thiz);
    
    //虽然JNI_OnLoad函数已经保存了JVM,但是那个没用.如果不调用env->GetJavaVM(&mVm); 会在线程中执行到myThreadProcessArray->mVm->AttachCurrentThread报错
    env->GetJavaVM(&mVm);
    pthread_t id;
    //通过pthread库创建线程
    LOGI("=========== create native thread ===========");
    if(pthread_create(&id,NULL, native_thread_exec, NULL)!=0)
    
        LOGI("=========== native thread create fail ===========");
        return;
    

6.JNI 在子线程生成字节数组并回调 Java 字节数组参数无返回值方法,并写入文件

public native void native_thread_call_java_byteArray_signature_callBack_method();
public String str2 = "";
public void callBack_writeFile(byte[] barr, int length)
    Log.e(TAG, "callBack: length = "+length);
    for (byte b : barr)
        str2+=b;
        str2+=", ";
    
    Log.e(TAG, "callBack_writeFile:  "+str2 );

    try 
        // 写入文件, 文件的路径在 /data/data/com.example.myjnicalljava/files/ 下面
        FileOutputStream fout = openFileOutput("test.txt", MODE_PRIVATE);
        fout.write(barr);
        fout.close();

        // 把刚才写入的内容,从文件中读出来
        FileInputStream fin = openFileInput("test.txt");
        byte[] readBuffer = new byte[length];
        fin.read(readBuffer);
        for (byte b : readBuffer)
            Log.e(TAG, "callBack_writeFile readBuffer:  "+b );
        
        fin.close();
        readBuffer = null;
     catch (FileNotFoundException e) 
        e.printStackTrace();
     catch (IOException e) 
        Log.e(TAG, "callBack_writeFile: IOException" );
        e.printStackTrace();
    
    runOnUiThread(
        new Runnable() 
            @Override
            public void run() 
                Toast.makeText(getApplicationContext(), "JNI在子线程生成字节数组并回调Java字节数组参数无返回值方法,JNI生成的字节数组为:"+str2, Toast.LENGTH_LONG).show();
            
        
    );

JavaVM* mVm = NULL;
jobject mObj = NULL;
void* native_thread_exec2(void* args)
    LOGI("=========== native_thread_exec ===========");
    JNIEnv *env;
    //从全局的JavaVM中获取到环境变量
    mVm->AttachCurrentThread(&env,NULL);
    jclass clazz = env->GetObjectClass(mObj);
    jmethodID postID = env->GetMethodID(clazz,"callBack_writeFile","([BI)V");

    jbyteArray jbarray = env->NewByteArray(5);//建立jbarray数组
    jbyte* pbarray = env->GetByteArrayElements(jbarray, NULL);
    pbarray[0] = 5;
    pbarray[1] = 9;
    pbarray[2] = 2;
    pbarray[3] = 3;
    pbarray[4] = 4;

    env->SetByteArrayRegion(jbarray, 0, 5, pbarray);            //将Jbyte 转换为jbarray数组
    env->CallVoidMethod(mObj, postID, jbarray, 5);
    env->ReleaseByteArrayElements(jbarray, pbarray, 0);
    mVm->DetachCurrentThread();
    pthread_exit(NULL);

extern "C"
JNIEXPORT void JNICALL
Java_com_example_myjnicalljava_MainActivity_native_1thread_1call_1java_1byteArray_1signature_1callBack_1method(
        JNIEnv *env, jobject thiz) 
    // TODO: implement native_thread_call_java_byteArray_signature_callBack_method()
    LOGI("=========== native_thread_call_java_byteArray_signature_callBack_method ===========");
    if (!mObj) 
        LOGI("=========== !mObj ===========");
        mObj = env->NewGlobalRef(thiz);
    
    //虽然JNI_OnLoad函数已经保存了JVM,但是那个没用.如果不调用env->GetJavaVM(&mVm); 会在线程中执行到myThreadProcessArray->mVm->AttachCurrentThread报错
    env->GetJavaVM(&mVm);
    pthread_t id;
    //通过pthread库创建线程
    LOGI("=========== create native thread ===========");
    if(pthread_create(&id,NULL, native_thread_exec2, NULL)!=0)
    
        LOGI("=========== native thread create fail ===========");
        return;
    

如果向pthread传递多个参数,可以将这多个参数封装在一个class里面,然后将这个class当作参数传递

以上是关于JNI调用Java方法的主要内容,如果未能解决你的问题,请参考以下文章

Java程序通过JNI调用C++程序的方法

Android Studio NDK开发-JNI调用Java方法

C通过JNI反向调用JAVA程序方法

如何从java本机接口调用getStackTrace方法(jni)

Java JNI实现调用自定义Native 方法

在windows下 如何使用java jni调用so文件