andriodAndroid知识

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

2017-11-13  本文已影响104人  zhang_pan

前言

前面我们已经介绍了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开发中的同步的问题,敬请期待!

上一篇下一篇

猜你喜欢

热点阅读