在Mono Droid中创建并将数组作为参数传递给JNI

本文关键字:参数传递 JNI 数组 Droid Mono 创建 | 更新日期: 2023-09-27 18:01:41

在mono Droid项目中,我有一个.java文件,其中包含以下类的定义:

class A
{
    String str;
    String[] arr;
    public A(string str, string[] arr) 
    {
        this.str = str;
        this.arr = arr;
    }
}

和一个方法foo(A[]),需要在c#中使用JNI环境调用。

在c#文件中,我有一个c#类的相应镜像定义

class B
{
    string str;
    string[] arr;
    ...
}

在一段c#代码中,我准备了B[]数组,现在想要将所有对象复制到一个新数组中,然后将该数组传递给方法。为此,我编写了一个方法B.ConvertArrayToJValue,它返回一个JValue

public class B
{
    string str;
    string[] arr;
    public B(string str, string[] arr) 
    {
        this.str = str;
        this.arr = arr;
    }
    public JValue ToJavaObject()
    {
        IntPtr classA = JNIEnv.FindClass("com/packagename/A");
        IntPtr method_ctor = JNIEnv.GetMethodID(classA, "<init>", "(Ljava/lang/String;[Ljava/lang/String;)V");
        Java.Lang.String.[] tempValues = new Java.Lang.String[this.arr.Length];
        for (int i = 0; i < this.arr.Length; ++i)
        {
            tempValues[i] = new Java.Lang.String(this.arr[i]);
        }
        JValue strArray = new JValue(Java.Lang.Object.FromArray<Java.Lang.String>(tempValues));
        IntPtr result = JNIEnv.NewObject(classA, method_ctor, new JValue[]{new JValue(new Java.Lang.String(this.str)), strArray});
        return new JValue(new Java.Lang.Object(result, JniHandleOwnership.DoNotTransfer));
    }
    public static JValue ConvertArrayToJValue(B[] arr)
    {
        JValue[] tempCopy = new JValue[arr.Length];
        for (int i = 0; i < arr.Length; ++i)
        {
            tempCopy[i] = arr[i].ToJavaObject();
        }
        //FIXME: doesn't properly convert arrays! 
        // Compiles but throws an exception in runtime: "Can't convert JValue to IJavaObject"
        return new JValue(Java.Lang.Object.FromArray<JValue>(tempCopy));
    }
}

和c#代码中的其他地方:

b[] = new B[]{ ... };
IntPtr method_foo = JNIEnv.GetStaticMethodID(classC, "foo", "([Lcom/packagename/A;)V");
JNIEnv.CallStaticVoidMethod(classC, method_foo, new JValue[] { B.ConvertArrayToJValue(b) });

这行不通。字符串数组似乎是正确生成的(至少它看起来像c#字符串转换为Java字符串(?)),但当我尝试创建自定义对象类型B的数组时,我得到一个错误:

Can't convert JValue to IJavaObject

谢谢!

在Mono Droid中创建并将数组作为参数传递给JNI

为什么在JValue结构中包装返回值?

我相信简单地从方法ToJavaObject返回IJavaObject应该工作。

:

public IJavaObject ToJavaObject()
{
    // Snip
    return new Java.Lang.Object(result, JniHandleOwnership.DoNotTransfer);
}
public static IJavaObject ConvertArrayToJavaObject(B[] arr)
{
    // Snip
    return Java.Lang.Object.FromArray<IJavaObject>(tempCopy);
}

我从一个Xamarin开发人员那里得到了以下可行的解决方案。它实际上对理解JNI的工作方式有很大帮助:

http://forums.xamarin.com/discussion/1930/creating-arrays-of-custom-java-objects-in-jni