Android NDK系列(5) — SO中获取Java对象的属性

我在博客上发表一些我的NDK学习心得,希望对大家能有帮助。 这一篇我们讲述如何在so中获取到Java对象属性

介绍

首先,之前写的文章中通过一个简单的例子从从Native中调用Java方法。

下面,我们要介绍的是如何在Native层中获取到Java对象属性

问题

首先,从Native层要操作Java对象的属性有两种方法:
1. 直接操作
2. 间接操作

来解释一下什么叫直接操作,即在Native层中直接获取到对象的属性,从而进行操作。间接操作是在Native层中操作相应对象的Get&Set方法来对属性进行操作,这个可以参考上一篇Native调用Java方法,原理是一样的。

继续从MyJni入手,定义一个变量n,其拥有Get&Set方法,如下所示:

public class MyJni {

    ......

    int n = 10;

    public void setN(int n) {
        this.n = n;
    }

    public int getN() {

        return n;
    }

    public native int nativeGetMyJniFieldN();
    public native void nativeSetN(int n);
    public native int nativeGetN();

    ......

}

实践

直接方法

在jni.h中:
定义了GetFieldID来获取对应类的属性ID

jfieldID    (*GetFieldID)(JNIEnv*, jclass, const char*, const char*);

定义GetXXXField SetXXXField函数,通过使用这个我们就可以来实现获取类中对应ID的属性调用方法。


jobject     (*GetObjectField)(JNIEnv*, jobject, jfieldID);
jboolean    (*GetBooleanField)(JNIEnv*, jobject, jfieldID);
jbyte       (*GetByteField)(JNIEnv*, jobject, jfieldID);
jchar       (*GetCharField)(JNIEnv*, jobject, jfieldID);
jshort      (*GetShortField)(JNIEnv*, jobject, jfieldID);
jint        (*GetIntField)(JNIEnv*, jobject, jfieldID);
jlong       (*GetLongField)(JNIEnv*, jobject, jfieldID);
jfloat      (*GetFloatField)(JNIEnv*, jobject, jfieldID) __NDK_FPABI__;
jdouble     (*GetDoubleField)(JNIEnv*, jobject, jfieldID) __NDK_FPABI__;

void        (*SetObjectField)(JNIEnv*, jobject, jfieldID, jobject);
void        (*SetBooleanField)(JNIEnv*, jobject, jfieldID, jboolean);
void        (*SetByteField)(JNIEnv*, jobject, jfieldID, jbyte);
void        (*SetCharField)(JNIEnv*, jobject, jfieldID, jchar);
void        (*SetShortField)(JNIEnv*, jobject, jfieldID, jshort);
void        (*SetIntField)(JNIEnv*, jobject, jfieldID, jint);
void        (*SetLongField)(JNIEnv*, jobject, jfieldID, jlong);
void        (*SetFloatField)(JNIEnv*, jobject, jfieldID, jfloat) __NDK_FPABI__;
void        (*SetDoubleField)(JNIEnv*, jobject, jfieldID, jdouble) __NDK_FPABI__;

Java层:

case R.id.button2:
    Log.d("123","" + myJni.n);
    Log.d("123", "nativeGetMyJniFieldN : " + myJni.nativeGetMyJniFieldN()); // 通过nativeGetMyJniField函数来获取n参数
    break;

Native层:

/*
 * Class:     com_example_qiuyu_testhellojni_MyJni
 * Method:    nativeGetMyJniFieldN
 * Signature: ()I
 */
JNIEXPORT jint JNICALL Java_com_example_qiuyu_testhellojni_MyJni_nativeGetMyJniFieldN
        (JNIEnv * env, jobject thiz) {
    jclass clazz = (*env)->GetObjectClass(env, thiz); // 先获取到对象的类,即myJni的类是MyJni
    //jfieldID    (*GetFieldID)(JNIEnv*, jclass, const char*, const char*); 
    jfieldID myjni_n = (*env)->GetFieldID(env, clazz, "n", "I"); // 获取到该类的对象"n"的ID,类型是int
    //jobject     (*GetObjectField)(JNIEnv*, jobject, jfieldID);
    return (*env)->GetIntField(env, thiz, myjni_n); // 通过执行GetXXXField函数来获取
}

间接方法

间接调用则比较简单,调用Set函数可以设置属性值,Get函数可以获取属性值,直接看代码:

Java:

case R.id.button3:
    Log.d("123","GET : " + myJni.nativeGetN()); // 先获取一下,输出
    myJni.nativeSetN(11); // 设置n
    Log.d("123","GET : " + myJni.nativeGetN()); // 输出n
    break;

Native:

/*
 * Class:     com_example_qiuyu_testhellojni_MyJni
 * Method:    nativeSetN
 * Signature: (I)V
 */
JNIEXPORT void JNICALL Java_com_example_qiuyu_testhellojni_MyJni_nativeSetN
        (JNIEnv * env, jobject thiz, jint n) {
    jclass clazz = (*env)->GetObjectClass(env, thiz);
    jmethodID setN = (*env)->GetMethodID(env,clazz,"setN","(I)V");
    (*env)->CallVoidMethod(env,thiz,setN,n);
}

/*
 * Class:     com_example_qiuyu_testhellojni_MyJni
 * Method:    nativeGetN
 * Signature: ()I
 */
JNIEXPORT jint JNICALL Java_com_example_qiuyu_testhellojni_MyJni_nativeGetN
        (JNIEnv * env, jobject thiz) {
    jclass clazz = (*env)->GetObjectClass(env, thiz);
    jmethodID getN = (*env)->GetMethodID(env,clazz,"getN","()I");
    return (*env)->CallIntMethod(env,thiz,getN);
}

源码

Github : https://github.com/QyMars/AndroidNativeCode

总结

这样,实现了简单C获取Java对象的属性,这样,Native层对于Java的操作更加灵活,好用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值