使本机代码访问java方法和数据成员

make native code access java methods and data members

本文关键字:数据成员 方法 java 本机代码 访问      更新时间:2023-10-16

我正在开发一个带有本地代码的android项目,该项目应该更新对象中的List和其他一些布尔变量。

考虑以下代码

我代码中的一些java类看起来像:

 class ReturnObject
{
    boolean a, b;
    public List<String[]> listA;
}
public class foo
{
    public native void someFunction(ReturnObject returnObject);
}

本地代码看起来像:

JNIEXPORT void JNICALL Java_com_example_androidtest_TestActivity_someFunction
  (JNIEnv * env, jobject jObj, jobject returnObject) {
    std::string f = "foo";
    // missing code here
    // returnObject.add(f) // add like in java
}

如何设置布尔变量的值?

对于List(知道我在本机代码中的数据存储为std::string),我如何从本机代码调用List类的add(String[] string)方法?

以下是设置布尔值的示例代码,遵循相同的准则调用列表的add方法。

#include <stdio.h>
#include <jni.h>
#include "com_example_Foo.h"
JNIEXPORT void JNICALL Java_com_example_Foo_someFunction
(JNIEnv *env, jobject object, jobject returnObject)
{
    jclass clzReturnObject = env->FindClass("com/example/ReturnObject");
    jfieldID fieldA = env->GetFieldID(clzReturnObject, "a", "Z");
    jfieldID fieldB = env->GetFieldID(clzReturnObject, "b", "Z");
    env->SetBooleanField(returnObject, fieldA, true);
    if (env->ExceptionCheck()) {
        fprintf(stderr, "error set boolean for a");
        env->ExceptionDescribe();
    }
    env->SetBooleanField(returnObject, fieldB, false);
    if (env->ExceptionCheck()) {
        fprintf(stderr, "error set boolean for b");
        env->ExceptionDescribe();
    }
    jfieldID fieldListID = env->GetFieldID(clzReturnObject, "list",
            "Ljava/util/List;");
    jobject listObject = env->GetObjectField(returnObject, fieldListID);
    jclass clzList = env->FindClass("java/util/List");
    jmethodID addMethodID = env->GetMethodID(clzList, "add",
            "(Ljava/lang/Object;)Z");
    jclass clzString = env->FindClass("java/lang/String");
    jstring initElement = env->NewStringUTF("0000");
    jobjectArray toAdd = env->NewObjectArray(10, clzString, initElement);
    if (env->ExceptionCheck()) {
        fprintf(stderr, "error create string array");
        env->ExceptionDescribe();
    }
    env->CallBooleanMethod(listObject, addMethodID, toAdd);
    env->DeleteLocalRef(initElement);
}

以下是java代码

public class Foo {
static {
    System.loadLibrary("Foo");
}
public static void main(String[] args) {
    ReturnObject returnObject = new ReturnObject();
    returnObject.list = new ArrayList<>();
    Foo foo = new Foo();
    foo.someFunction(returnObject);
    System.out.println("size is " + returnObject.list.size());
    foo.someFunction(returnObject);
    System.out.println("size is " + returnObject.list.size());
    foo.someFunction(returnObject);
    System.out.println("size is " + returnObject.list.size());
    // we have three element added from JNI
    for (String string : returnObject.list.get(2)) {
        System.out.println(string);
    }
}
public native void someFunction(ReturnObject returnObject);
}

这里有一个调用字符串构造函数在JNI中创建jstring的例子。

jbyteArray initValue = env->NewByteArray(10);
env->SetByteArrayRegion(initValue, 0, 9, (const signed char*)"ABCDEFG");
jstring enc = env->NewStringUTF("UTF-8");
jclass clzString = env->FindClass("java/lang/String");
jmethodID cMethodID = env->GetMethodID(clzString, "<init>", "([BLjava/lang/String;)V");
jstring result = reinterpret_cast<jstring>(env->NewObject(clzString, cMethodID, initValue, enc));

以下是从JNI读取EditText文本的示例。

void Java_com_example_foo_MainActivity_someFunction(JNIEnv* env, jobject object,
    jstring objString, jobject objEditText) {
    __android_log_print(ANDROID_LOG_INFO, "Foo", "%sn", "JNI call");
    // get edittext value
    jclass clzEditText = env->GetObjectClass(objEditText);
    jmethodID methodGetText = env->GetMethodID(clzEditText, "getText", "()Landroid/text/Editable;");
    jobject objEditable = env->CallObjectMethod(objEditText, methodGetText);
    jclass clzEditable = env->GetObjectClass(objEditable);
    jmethodID methodToString = env->GetMethodID(clzEditable, "toString", "()Ljava/lang/String;");
    jstring editText = reinterpret_cast<jstring>(env->CallObjectMethod(
        objEditable, methodToString));
    jboolean isCopy = true;
    __android_log_print(ANDROID_LOG_INFO, "Foo", "From java: %sn", env->GetStringUTFChars(editText, &isCopy));
}

假设在应用程序的MainActivity中声明了一个jni。

private native void someFunction(String s, EditText editText);

我没有找到一个好的解决方案来直接从JNI设置String。如果您想在JNI中操作String,您可以将结果从返回值传递给Java。

private native String Foo();