美文网首页
Android NDK - JNI中回调Java中的函数

Android NDK - JNI中回调Java中的函数

作者: chengjian666 | 来源:发表于2018-02-22 14:33 被阅读524次

    在实际应用中,除了在JNI层对部分功能进行C++的实现,同时还会有在JNI中对Java函数的调用以实现某种逻辑的联通。
    在JNI中回调Java函数,实际上是通过反射机制来实现的,通过反射机制取得目标函数所在的类,以及其名称,通过NDK提供的接口在JNI层进行调用。

    JNI中调用Java函数的栗子

    • TestFunction.java
    package com.test.jni;
    public class TestFunction {
        
        public static void testFunc(){
            Log.d("tag from Java", "worked!");
        }
    }
    
    • TestFunctionJNI.cpp
    const char[] method_class_from_java = "com/teest/jni/TestFunction";
    const char[] method_name_from_java = "testFunc";
    jclass cls_str_id = jenv->FindClass(method_from_java);
    jmethodID m_Java_TestFunc = jenv->GetStaticMethodID(cls_str_id, method_name_from_java, "()V");
    jenv->CallStaticObjectMethod(cls_str_id, m_Java_TestFunc);
    

    通过如上方式就可以实现在JNI中调用Java中函数,具体解释如下:

    • 通过反射获取函数所在类的jclass;
    • 通过反射获取目标函数的id;
    • 通过NDK提供的接口实现调用;

    其中jenv为JNI函数的环境参数,注意在反射获取java函数时其参数及返回值数据类型的签名。

    NDK中数据类型签名规则

    关于NDK中的签名规则如下:

    字符签名 jni中类型 java中类型
    V void void
    Z jboolean boolean
    I jint int
    J jlong long
    D jdouble double
    F jfloat float
    B jbyte byte
    C jchar char
    S jshort short
    字符签名 jni中类型 java中类型
    [Z jbooleanArray boolean[]
    [I jintArray int[]
    [J jlongArray long[]
    [D jdoubleArray double[]
    [F jfloatArray float[]
    [B jbyteArray byte[]
    [C jcharArray char[]
    [S jshortArray short[]

    而对于数组而言,需要以"["开始,组合以上规则即可,具体对应关系表如下:

    字符签名 jni中类型 java中类型
    [Z jbooleanArray boolean[]
    [I jintArray int[]
    [J jlongArray long[]
    [D jdoubleArray double[]
    [F jfloatArray float[]
    [B jbyteArray byte[]
    [C jcharArray char[]
    [S jshortArray short[]

    以上均为基本数据类型的签名,对于另外两种情况:

    1. Java类(包括自定义类)
      对于参数或者返回值类型是Java类的情况,需要以"L"开头,并且以";"结束,并且以"/"隔开包名路径,并且此时在JNI中其对应接收的类型为jobject, 而对于基本数据类型,则使用其对应的NDK中的数据类型表示即可。比如:
    "Landroid/os/FileUtils;"
    
    1. Java内部类
      对于参数或者返回值类型是Java类中的内部类的情况,则需要在以上基础结合"$"索引,比如:
    "Landroid/os/FileUtils$FileStatus;"
    

    讲到这里,基本上十分清楚了,但是有一个特殊情况,细心的同学应该可以发现,以上列表中我们并没有标记String类型。那是因为确实存在一个例外情况一定要当心,那就是String类。在使用其签名时,要使用:

    "Ljava/lang/String;"
    

    如果直接使用jstring,那就会找不到。这个例外情况一定要当心。

    JNI中的 JNIEnv 和 jobject

    在每个JNI对Java层开发的native函数中,第一第二个参数均是如下形式:

    static void JNICALL test (JNIEnv *jenv, jobject obj)
    
    • JNIEnv
      该参数代表Java环境,通过这个环境可以调用Java中的函数,这些函数可以在jni.h中查到,通过这些函数可以实现Java与JNI层的交互,通过JNIEnv调用JNI函数可以访问java虚拟机,操作java对象;
      JNIEnv在在当前的线程有效,JNIEnv不能跨线程传递,相同的Java线程调用本地方法所使用的JNIEnv是相同的,一个native函数不能被不同的Java线程调用;该JNIEnv只想一个线程相关的结构,想成相关结构只想一个指针数组,指针数组中的内阁元素最终就会指向某一个JNI函数;
    • jobject
      该参数代表调用jni函数的Java类或者对象,如果native方法是非静态的,那么这个参数就是对Java对象的引用,如果native函数是静态的,那么这个参数就是对Java类的class对象的引用;
      CSDN同步发布地址

    相关文章

      网友评论

          本文标题:Android NDK - JNI中回调Java中的函数

          本文链接:https://www.haomeiwen.com/subject/mrqztftx.html