Android Studio NDK开发(三):属性访问

前言

前面我们已经在Android Studio中创建支持C/C++的项目了,并能调用native方法,返回字符串,展示在界面中,如果对此不了解的话,可以查看之前的博客:Android Studio NDK开发(二):Welcome to JNI
下面我将介绍native函数访问Java中的属性

Java基本数据类型与JNI的映射关系

Java类型<-->JNI类型<-->C类型

JNI基本数据类型(左边是Java,右边是JNI)

boolean     jboolean;
byte        jbyte;
char        jchar;
short       jshort;
int         jint;
long        jlong;
float       jfloat;
double      jdouble;
void        void

JNI引用数据类型(左边是Java,右边是JNI)

String                    jstring
Object                    jobject
//基本数据类型的数组
byte[]                   jByteArray
//对象数组
Object[](String[])      jobjectArray

由于在属性、方法访问当中需要用到签名,接下来我们来看看签名:

属性与方法的签名

属性的签名

Android Studio NDK开发(三):属性访问_第1张图片
1.png

方法的签名

方法的签名稍显麻烦,我们可以在Android Studio中配置javap -s -p,来生成某个类所有的属性、方法的签名。
在Android Studio中,选择file -> settings -> 输入tools -> 选择External Tools:

Android Studio NDK开发(三):属性访问_第2张图片
2.png

这里由于我已经添加了javap -s -p,所以这里已经有了相关配置,可不必理睬。现在我们来进行配置,点击第三步,出现:

Android Studio NDK开发(三):属性访问_第3张图片
3.png

配置后:

Android Studio NDK开发(三):属性访问_第4张图片
4.png

点击ok,这样我们就可以查看某个方法的签名了,选择该方法所属类,比如MainActivity,点击Tools -> External Tools -> javap -s -p

Android Studio NDK开发(三):属性访问_第5张图片
4.png

可以看到生成了该类所有的签名(如果不行,可以Rebuild Project或者Make Project,再执行javap -s -p命令):

Android Studio NDK开发(三):属性访问_第6张图片
5.png

访问Java非静态属性

我们需要做的是native函数访问Java的非静态属性,并改变Java中非静态属性的值。
首先在MainActivity(可自己起名字,也可以是Java类)中定义一个非静态属性key,也就是native函数需要访问的Java属性

public String key = "john";

在MainActivity中定义一个native方法

//访问属性
public native void accessField();

由于需要判断更改后的值是否一样,所以在MainActivity中的onCreate()中调用并打印

System.out.println("修改前:" + key);
this.accessField();
System.out.println("修改后:" + key);

当然基本的配置,比如System.loadLibray,CMakeLists的配置是少不了的,有不清楚的,可以查看我的NDK开发系列的Android NDK开发(一)、(二),这里就不做赘述了。
再来看看native函数的实现:

//C/C++访问Java的成员
//访问非静态属性
JNIEXPORT void JNICALL
Java_com_zhangpan_myjnicmake_MainActivity_accessField(JNIEnv *env, jobject jobj) {
    //得到jclass
    jclass jcla = (*env)->GetObjectClass(env, jobj);
    //得到jfieldID,最后一个参数是签名,String对应的签名是Ljava/lang/String;(注意最后的分号)
    jfieldID  jfID = (*env)->GetFieldID(env, jcla, "key", "Ljava/lang/String;");
    //得到key属性的值jstring
    jstring jstr = (*env)->GetObjectField(env, jobj, jfID);
    //jstring转化为C中的char*
    char* oriText = (*env)->GetStringUTFChars(env, jstr, NULL);
    //拼接得到新的字符串text="China John"
    char text[20] = "China ";
    strcat(text, oriText);
    //C中的char*转化为JNI中的jstring
    jstring jstrMod = (*env)->NewStringUTF(env, text);
    //修改key
    (*env)->SetObjectField(env, jobj, jfID, jstrMod);
    //只要使用了GetStringUTFChars,就需要释放
    (*env)->ReleaseStringUTFChars(env, jstr, oriText);
}

具体JNI的api可看上面的注释,这里就不细说了,有一定的规律可寻,大家动手做做,相信问题不大。
打印输出:

修改前:john
修改后:China john

访问Java静态属性

首先定义一个Java静态属性

private static int count = 10;

再定义一个native方法

//访问静态属性
public native void accessStaticField();

在MainActivity onCreate中调用打印

System.out.println("修改前count:" + count);
accessStaticField();
System.out.println("修改后count:" + count);

native函数的实现

//访问静态属性
JNIEXPORT void JNICALL
Java_com_zhangpan_myjnicmake_MainActivity_accessStaticField(JNIEnv *env, jobject jobj) {
    //得到jclass
    jclass jcla = (*env)->GetObjectClass(env, jobj);
    //得到jfieldID
    jfieldID jfid = (*env)->GetStaticFieldID(env, jcla, "count", "I");
    //得到静态属性的值count
    jint count = (*env)->GetStaticIntField(env, jcla, jfid);
    //自增
    count++;
    //修改count的值
    (*env)->SetStaticIntField(env, jcla, jfid, count);
}

项目地址

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

展望

本篇博客介绍了如何在native函数中访问Java的属性,下一篇博客我们将介绍如何在native函数中访问Java的方法,敬请期待!

你可能感兴趣的:(Android Studio NDK开发(三):属性访问)