美文网首页andriodAndroid知识
Android Studio NDK开发(四):方法访问

Android Studio NDK开发(四):方法访问

作者: zhang_pan | 来源:发表于2017-11-13 23:36 被阅读104次

    前言

    前面我们已经介绍了native函数访问Java的属性,如果对此不是很了解的话,可以看博客Android Studio NDK开发(三):属性访问
    本篇博客将介绍native函数访问Java的方法

    访问Java非静态方法

    首先在MainActivity(可自定义,可以是Java类)中定义一个方法,也就是native函数访问的Java非静态方法

     //产生指定范围的随机数
     public int getRandomInt(int value) {
            System.out.println("getRandomInt 执行了");
            return new Random().nextInt(value);
        }
    

    然后在MainActivity中再定义一个native方法,此方法的native函数实现就是去调用上面的getRandomInt,来实现native函数访问Java非静态方法

    public native void accessMethod();
    

    在onCreate中调用

    accessStaticMethod();
    

    至于JNI的配置信息,这里就不做赘述,不明白的,可以看我之前的博客,或者可以下载项目地址,查看代码。接下来就是native函数实现了:

    JNIEXPORT void JNICALL
    Java_com_zhangpan_myjnicmake_MainActivity_accessMethod(JNIEnv *env, jobject jobj) {
        //得到jclass
        jclass jcla = (*env)->GetObjectClass(env, jobj);
        //得到jmethodID
        jmethodID jmid = (*env)->GetMethodID(env, jcla, "getRandomInt", "(I)I");
        //调用java方法获取返回值,第四个参数100表示传入到java方法中的值
        jint jRandom = (*env)->CallIntMethod(env, jobj, jmid, 100);
        //可以在Android Studio中Logcat显示,需要定义头文件#include <android/log.h>
        __android_log_print(ANDROID_LOG_DEBUG, "system.out", "Random:%ld", jRandom);
    }
    

    运行之后,打印的结果为:

    getRandomInt 执行了
    Random:56
    

    访问Java中静态方法

    定义一个静态方法

    //产生UUID字符串
        public static String getUUID() {
            return UUID.randomUUID().toString();
        }
    

    再定义一个native方法

    public native void accessStaticMethod();
    

    在onCreate中调用

    accessStaticMethod();
    

    native函数的实现

    JNIEXPORT void JNICALL
    Java_com_zhangpan_myjnicmake_MainActivity_accessStaticMethod(JNIEnv *env, jobject jobj) {
        jclass jcla = (*env)->GetObjectClass(env, jobj);
        jmethodID  jmid = (*env)->GetStaticMethodID(env, jcla, "getUUID", "()Ljava/lang/String;");
        jstring uuid = (*env)->CallStaticObjectMethod(env, jcla, jmid);
        char* uuid_str = (*env)->GetStringUTFChars(env, uuid, NULL);
        __android_log_print(ANDROID_LOG_DEBUG, "system.out", "uuid_str:%ld", uuid_str);
    }
    

    运行打印:

    uuid_str:368008644224
    

    访问Java中构造方法

    我们来实现访问Java中的Date构造方法,实例化Date对象,再利用这个对象调用getTime产生一个时间戳,并打印其值。
    定义一个native方法

    public native void accessConstructor();
    

    在MainActivity的onCreate中调用

    accessConstructor();
    

    native函数的实现

    JNIEXPORT void JNICALL
    Java_com_zhangpan_myjnicmake_MainActivity_accessConstructor(JNIEnv *env, jobject jobj) {
        //得到类Date对应的jclass
        jclass jcla = (*env)->FindClass(env, "java/util/Date");
        //构造方法对应的都是<init>
        //在任意位置打开命令行,输入javap -s -p java.util.Date可以看到空参构造的签名是()V
        jmethodID jmid = (*env)->GetMethodID(env, jcla, "<init>", "()V");
        //实例化Date对象
        jobject jDate = (*env)->NewObject(env, jcla, jmid);
        //下面需要调用的是getTime,对应这里第三个参数传入getTime,第四个参数为其签名
        jmethodID jTimeMid = (*env)->GetMethodID(env, jcla, "getTime", "()J");
        //调用getTime方法得到返回值jlong
        jlong jtime = (*env)->CallLongMethod(env, jDate, jTimeMid);
    
        __android_log_print(ANDROID_LOG_DEBUG, "system.out", "jtime:%ld", jtime);
    }
    

    运行打印结果:

    jtime:1510550749157
    

    访问Java中父类的方法

    首先我们需要有一个父类和一个子类,子类重写了父类的方法,创建一个Animal类,并创建其子类Cat类

    public class Animal {
        public void eat() {
            System.out.println("动物吃肉...");
        }
    }
    
    public class Cat extends Animal {
        @Override
        public void eat() {
            System.out.println("猫吃鱼...");
        }
    }
    

    在MainActivity中创建native方法

    JNIEXPORT void JNICALL
    Java_com_zhangpan_myjnicmake_MainActivity_accessNonvirtualMethod(JNIEnv *env, jobject jobj) {
        //得到MainActivity对应的jclass
        jclass  jcla = (*env)->GetObjectClass(env, jobj);
        //得到animal属性对应的jfieldID
        jfieldID jfid = (*env)->GetFieldID(env, jcla, "animal", "Lcom/zhangpan/myjnicmake/Animal;");   //这里必须是父类对象的签名,否则会报NoSuchFieldError,因为Java中是父类引用指向子类对象
        //得到animal属性对应的jobject
        jobject animalObj = (*env)->GetObjectField(env, jobj, jfid);
    //    jclass animalCla =(*env)->GetObjectClass(env, animalObj); //这种方式,下面调用CallNonvirtualVoidMethod会执行子类的方法
        //找到Animal对应的jclass
        jclass animalCla = (*env)->FindClass(env, "com/zhangpan/myjnicmake/Animal");   //如果这里写成子类的全类名,下面调用CallNonvirtualVoidMethod会执行子类的方法
        //得到eat对应的jmethodID
        jmethodID eatID = (*env)->GetMethodID(env, animalCla, "eat", "()V");
    //    (*env)->CallVoidMethod(env, animalCla, eatID);      //这样调用会报错
        //调用父类的方法
        (*env)->CallNonvirtualVoidMethod(env, animalObj, animalCla, eatID);     //输出父类的方法
    }
    

    运行打印结果:

    动物吃肉...
    

    项目地址

    https://github.com/fsrmeng/MyJniCmake-Master

    展望

    上面我们总结了native函数访问Java的各类方法,下篇博客我将带大家介绍NDK开发中的同步的问题,敬请期待!

    相关文章

      网友评论

        本文标题:Android Studio NDK开发(四):方法访问

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