Android Studio NDK開發(fā)(三):屬性訪問

前言

前面我們已經(jīng)在Android Studio中創(chuàng)建支持C/C++的項(xiàng)目了,并能調(diào)用native方法,返回字符串,展示在界面中,如果對(duì)此不了解的話,可以查看之前的博客:Android Studio NDK開發(fā)(二):Welcome to JNI
下面我將介紹native函數(shù)訪問Java中的屬性

Java基本數(shù)據(jù)類型與JNI的映射關(guān)系

Java類型<-->JNI類型<-->C類型

JNI基本數(shù)據(jù)類型(左邊是Java,右邊是JNI)

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

JNI引用數(shù)據(jù)類型(左邊是Java,右邊是JNI)

String                    jstring
Object                    jobject
//基本數(shù)據(jù)類型的數(shù)組
byte[]                   jByteArray
//對(duì)象數(shù)組
Object[](String[])      jobjectArray

由于在屬性、方法訪問當(dāng)中需要用到簽名,接下來我們來看看簽名:

屬性與方法的簽名

屬性的簽名

1.png

方法的簽名

方法的簽名稍顯麻煩,我們可以在Android Studio中配置javap -s -p,來生成某個(gè)類所有的屬性、方法的簽名。
在Android Studio中,選擇file -> settings -> 輸入tools -> 選擇External Tools:

2.png

這里由于我已經(jīng)添加了javap -s -p,所以這里已經(jīng)有了相關(guān)配置,可不必理睬。現(xiàn)在我們來進(jìn)行配置,點(diǎn)擊第三步,出現(xiàn):

3.png

配置后:

4.png

點(diǎn)擊ok,這樣我們就可以查看某個(gè)方法的簽名了,選擇該方法所屬類,比如MainActivity,點(diǎn)擊Tools -> External Tools -> javap -s -p

4.png

可以看到生成了該類所有的簽名(如果不行,可以Rebuild Project或者M(jìn)ake Project,再執(zhí)行javap -s -p命令):

5.png

訪問Java非靜態(tài)屬性

我們需要做的是native函數(shù)訪問Java的非靜態(tài)屬性,并改變Java中非靜態(tài)屬性的值。
首先在MainActivity(可自己起名字,也可以是Java類)中定義一個(gè)非靜態(tài)屬性key,也就是native函數(shù)需要訪問的Java屬性

public String key = "john";

在MainActivity中定義一個(gè)native方法

//訪問屬性
public native void accessField();

由于需要判斷更改后的值是否一樣,所以在MainActivity中的onCreate()中調(diào)用并打印

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

當(dāng)然基本的配置,比如System.loadLibray,CMakeLists的配置是少不了的,有不清楚的,可以查看我的NDK開發(fā)系列的Android NDK開發(fā)(一)、(二),這里就不做贅述了。
再來看看native函數(shù)的實(shí)現(xiàn):

//C/C++訪問Java的成員
//訪問非靜態(tài)屬性
JNIEXPORT void JNICALL
Java_com_zhangpan_myjnicmake_MainActivity_accessField(JNIEnv *env, jobject jobj) {
    //得到j(luò)class
    jclass jcla = (*env)->GetObjectClass(env, jobj);
    //得到j(luò)fieldID,最后一個(gè)參數(shù)是簽名,String對(duì)應(yīng)的簽名是Ljava/lang/String;(注意最后的分號(hào))
    jfieldID  jfID = (*env)->GetFieldID(env, jcla, "key", "Ljava/lang/String;");
    //得到key屬性的值jstring
    jstring jstr = (*env)->GetObjectField(env, jobj, jfID);
    //jstring轉(zhuǎn)化為C中的char*
    char* oriText = (*env)->GetStringUTFChars(env, jstr, NULL);
    //拼接得到新的字符串text="China John"
    char text[20] = "China ";
    strcat(text, oriText);
    //C中的char*轉(zhuǎn)化為JNI中的jstring
    jstring jstrMod = (*env)->NewStringUTF(env, text);
    //修改key
    (*env)->SetObjectField(env, jobj, jfID, jstrMod);
    //只要使用了GetStringUTFChars,就需要釋放
    (*env)->ReleaseStringUTFChars(env, jstr, oriText);
}

具體JNI的api可看上面的注釋,這里就不細(xì)說了,有一定的規(guī)律可尋,大家動(dòng)手做做,相信問題不大。
打印輸出:

修改前:john
修改后:China john

訪問Java靜態(tài)屬性

首先定義一個(gè)Java靜態(tài)屬性

private static int count = 10;

再定義一個(gè)native方法

//訪問靜態(tài)屬性
public native void accessStaticField();

在MainActivity onCreate中調(diào)用打印

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

native函數(shù)的實(shí)現(xiàn)

//訪問靜態(tài)屬性
JNIEXPORT void JNICALL
Java_com_zhangpan_myjnicmake_MainActivity_accessStaticField(JNIEnv *env, jobject jobj) {
    //得到j(luò)class
    jclass jcla = (*env)->GetObjectClass(env, jobj);
    //得到j(luò)fieldID
    jfieldID jfid = (*env)->GetStaticFieldID(env, jcla, "count", "I");
    //得到靜態(tài)屬性的值count
    jint count = (*env)->GetStaticIntField(env, jcla, jfid);
    //自增
    count++;
    //修改count的值
    (*env)->SetStaticIntField(env, jcla, jfid, count);
}

項(xiàng)目地址

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

展望

本篇博客介紹了如何在native函數(shù)中訪問Java的屬性,下一篇博客我們將介紹如何在native函數(shù)中訪問Java的方法,敬請(qǐng)期待!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容