现在的位置: 首页 > 综合 > 正文

android NDK 入门之在JNI中修改java中对象的成员变量的值

2013年10月06日 ⁄ 综合 ⁄ 共 4323字 ⁄ 字号 评论关闭
android NDK 入门之在JNI中修改java中对象的成员变量的值
如题:测试在JNI中修改java代码中成员变量的值

JavaBean类编写如下
package com.xl.qiu;

public class StepByStepInstance {
    public native void changeStepInstanceString();
    
    public StepByStepInstance(String str1)
    {
        this.str1 = str1;
    }
    
    private String str1;

    public String getStr1() {
        return str1;
    }

    public void setStr1(String str1) {
        this.str1 = str1;
    }
    
    
}

调用处Java代码如下:
                StepByStepInstance step = new StepByStepInstance("step");

                step.changeStepInstanceString();

javah 工具生成.h头文件如下:

#include <jni.h>
/* Header for class com_xl_qiu_StepByStepInstance */

#ifndef _Included_com_xl_qiu_StepByStepInstance
#define _Included_com_xl_qiu_StepByStepInstance
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_xl_qiu_StepByStepInstance
 * Method:    changeStepInstanceString
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_xl_qiu_StepByStepInstance_changeStepInstanceString
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

编写c语言代码如下:

JNIEXPORT void JNICALL Java_com_xl_qiu_StepByStepInstance_changeStepInstanceString(JNIEnv *env, jobject this) {
    jfieldID fid;
    jstring jstr;
    const char *str;
    
    jclass cls = (*env)->GetObjectClass(env, this);
    
    fid = (*env)->GetFieldID(env, cls, "str1", "Ljava/lang/String;");

    if (fid == NULL)
        return;

    jstr = (*env)->GetObjectField(env, this, fid);
    str = (*env)->GetStringUTFChars(env, jstr, NULL);

    if (str ==  NULL)
        return;

    __android_log_print(ANDROID_LOG_INFO, "JNI", "In C Str:%s, Change in StepByStepInstance.java", str);

    (*env)->ReleaseStringUTFChars(env, jstr, str);

    jstr = (*env)->NewStringUTF(env, "New String Given By C, Change field int StepByStepInstance.java");

    if (jstr == NULL)
        return;

    (*env)->SetObjectField(env, this, fid, jstr);
    
}   

简单解释一下JNI代码中几个调用的函数:

GetObjectClass 

jclass GetObjectClass(JNIEnv *env, jobject obj); 

返回对象的类。

参数:

env:JNI 接口指针。 

obj:Java 对象(不能为 NULL)。

返回值:

返回 Java 类对象。


GetFieldID 

jfieldID GetFieldID(JNIEnv *env, jclass clazz, 
const char *name, const char *sig); 

返回类的实例(非静态)域的域 ID。该域由其名称及签名指定。访问器函数的 Get<type>Field 及 Set<type>Field 系列使用域 ID 检索对象域。 

GetFieldID() 将未初始化的类初始化。

GetFieldID() 不能用于获取数组的长度域。应使用 GetArrayLength()。

参数:

env:JNI 接口指针。 

clazz:Java 类对象。

name: 0 终结的 UTF-8 字符串中的域名。

sig:0 终结的 UTF-8 字符串中的域签名。

返回值:

域 ID。如果操作失败,则返回 NULL。

Get<type>Field 例程 

NativeType Get<type>Field(JNIEnv *env, jobject obj, 
jfieldID fieldID); 

该访问器例程系列返回对象的实例(非静态)域的值。要访问的域由通过调用 GetFieldID() 而得到的域 ID 指定。

Set<type>Field 例程 

void Set<type>Field(JNIEnv *env, jobject obj, jfieldID fieldID,
NativeType value); 

NewStringUTF 

jstring NewStringUTF(JNIEnv *env, const char *bytes); 

利用 UTF-8 字符数组构造新 java.lang.String 对象。

参数:

env:JNI 接口指针。如果无法构造该字符串,则为 NULL。

bytes:指向 UTF-8 字符串的指针。

返回值:

Java 字符串对象。如果无法构造该字符串,则为 NULL。

ReleaseStringUTFChars 

void ReleaseStringUTFChars(JNIEnv *env, jstring string,
const char *utf); 

通知虚拟机平台相关代码无需再访问 utf。utf 参数是一个指针,可利用 GetStringUTFChars() 从 string 获得。 

参数:

env:JNI 接口指针。 

string:Java 字符串对象。

utf:指向 UTF-8 字符串的指针。



如上介绍了如何修改类成员变量(非静态,下面继续介绍如何修改静态类成员变量):

同样是StepByStepInstance类
我们添加类静态成员public static int static_i;
同样添加一个本地方法用来JNI修改static_i;
public native void changeStaticField();

.h文件中增加了方法声明:
JNIEXPORT void JNICALL Java_com_xl_qiu_StepByStepInstance_changeStaticField
  (JNIEnv *, jobject);

c语言代码实现如下:

JNIEXPORT void JNICALL
    Java_com_xl_qiu_StepByStepInstance_changeStaticField(
                                                        JNIEnv *env,
                                                        jobject this)
{
    jfieldID fid;
    jint si;
    
    jclass cls = (*env)->GetObjectClass(env, this);
    
    fid = (*env)->GetStaticFieldID(env, cls, "static_i", "I");
    if (fid == NULL)
        return;

    si = (*env)->GetStaticIntField(env, cls, fid);
        
    __android_log_print(ANDROID_LOG_INFO, "JNI", "In C Str:%d, given by StepByStepInstance.java", si);

    (*env)->SetStaticIntField(env, cls, fid, ++si);
}

JNI函数介绍:

SetStatic<type>Field 例程 

void SetStatic<type>Field(JNIEnv *env, jclass clazz, 
jfieldID fieldID, NativeType value); 

该访问器例程系列设置对象的静态域的值。要访问的域由通过调用 GetStaticFieldID() 而得到的域 ID 指定。

GetStatic<type>Field 例程

NativeType GetStatic<type>Field(JNIEnv *env, jclass clazz,
jfieldID fieldID); 

该访问器例程系列返回对象的静态域的值。要访问的域由通过调用 GetStaticFieldID() 而得到的域 ID 指定。

上述JNI代码中用到了字段描述符:

一个特殊的 C字符串“Ljava/lang/String”来代表一个JVM 中的字段类
型。这个字符串被称为JNI field descriptor(字段描述符)。 
字符串的内容由字段被声明的类型决定。例如,使用“I”来表示一个int类型的字段,“F”
来表示一个float类型的字段,“D”来表示一个double 类型的字段,“Z”来表示一个 boolean
类型的字段等等。 
像java.lang.String这样的引用类型的描述符都是以L开头,后面跟着一个JNI类描述符,以
分号结尾。一个JAVA 类的全名中的包名分隔符“.”被转化成“/”。因此,对于一个字段类
型的字段来说,它的描述符是“Ljava/lang/String”。 数组的描述符中包含“]”字符

【上篇】
【下篇】

抱歉!评论已关闭.