GWT:如何将Java数组传递到JavaScript本地方法中?

4

我有一个Java字符串数组,现在想将其传递到JSNI函数中。我尝试使用GWT中的JsArrayString,但是我发现它无法直接初始化,因为它没有可见的构造函数。那么我该如何将我的字符串数组传递到JSNI函数并在我的JavaScript代码中使用它呢?代码看起来像下面这样:

public void callJSNI() {
    String[] stringArray = xxx;

    //How should I convert the array into a JSNI-readable format here?
}

private native void JSNIMethod(JsArrayString array) /*-{
    //some code to use the array in javascript
}-*/

不行。GWT文档称Java数组对JSNI是不透明的。 - Yuhao
3个回答

6

API没有提供简单的方法来实现这一点,您需要创建一个实用方法来做到以下几点:

  1. 创建一个新的JSNI数组
  2. 遍历Java数组参数并填充JSNI数组

就像这样:

public static JsArrayString toJsArray(String[] input) {
    JsArrayString jsArrayString = createEmptyJsArrayString();
    for (String s : input) {
        jsArrayString.push(s);
    }
    return jsArrayString; 
}

private static native JsArrayString createEmptyJsArrayString() /*-{
    return [];
}-*/;

根据OP的建议,我们当然可以跳过本机初始化并使用JsArrayString.createArray()

现在我们可以摆脱本机初始化,所以我们的代码减少到了这个样子:

public static JsArrayString toJsArray(String[] input) {
JsArrayString jsArrayString = JsArrayString.createArray().cast();
    for (String s : input) {
        jsArrayString.push(s);
    }
    return jsArrayString; 
}

可以使用 JsArrayString.createArray()。我在我的程序中测试过,它可以正常工作。你的解决方案看起来也很不错! - Yuhao
你说得对,我正在更新以包含这个。谢谢。 - Eliran Malka
没问题。如果您更新答案并包含我的方法,我会接受您的答案。 :-) - Yuhao

5

Eliran Malka的答案是一个不错的起点。但请注意,有一种更高效的扩展解决方案适用于某些情况。这就是为什么我创建另一个答案的原因。

简单的解决方案如下:

public static JsArrayString toJsArray(String[] input) {
    JsArrayString jsArrayString = JsArrayString.createArray().cast();
    for (String s : input) {
        jsArrayString.push(s);
    }
    return jsArrayString; 
}

更高效的解决方案需要一些背景知识...

GWT编译器在Java代码使用Java数组时使用JS数组。所以在这种情况下,您已经有了一个JS数组。但是这可能会导致副作用,在Dev和Prod模式下产生不同的行为:

由于在Dev模式下我们有真正的Java数组,因此始终需要通过复制值将其转换为JS数组。对其中一个数组的操作对另一个数组不可见。

在Prod模式下,如果我们直接使用Java数组作为JS数组,那么我们只会有一个数组。因此,无论是Java代码还是JS代码中的操纵都会影响其他世界。

但是,如果您的用例符合以下条件,则可以在不创建另一个数组的情况下使用该数组:

  • 以下其中之一必须为真
    • JS代码根本没有操作数组
    • 在将数组传递给JSNI方法后,Java代码不再使用该数组
  • 以下其中之一必须为真
    • JS代码仅在其中使用一次该数组(JS代码不会创建超出本机方法调用的数组引用)
    • Native调用后,Java代码不操纵该数组。

在这种情况下,您将没有副作用(Dev和Prod模式下的不同行为),并且可以直接在本机代码中使用该数组。

这种实现包含在GWT的JsArrayUtils中。但是,很遗憾目前没有String数组的实现。但是实现将如下所示:

public static JsArrayString readOnlyJsArray(String[] array) {
    if (GWT.isScript()) {
        return arrayAsJsArrayForProdMode(array).cast();
    }
    JsArrayString dest = JsArrayString.createArray().cast();
    for (int i = 0; i < array.length; ++i) {
        dest.push(array[i]);
    }
    return dest;
}
private static native JavaScriptObject arrayAsJsArrayForProdMode(Object array) /*-{
    return array;
}-*/;

在你的代码中,参数String[] readOnlyJsArray应该改为String[] array吗?因为这样对我来说更有意义。 - Yuhao

2

我最终自己找到了答案。

JsArrayString 可以通过 JsArrayString.createArray() 进行“初始化”,然后你可以像在javascript中一样进行任何操作。


是的,createArray() 是一个很好的包装器,用于返回 JSNI 表示形式([])。 - Eliran Malka

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接