如何在Java Applet中注册JavaScript回调函数?

10

我正在开发一个看不见的Java Applet,它将完全由JavaScript控制。

我可以轻松地调用applet的Java方法,并且我可以使用netscape.javascript.JSObject.getWindow(this).call()在applet内部调用JavaScript方法。

但是为了在applet中注册JavaScript回调,我想我需要某种JavaScript函数对象。

我想做到:

public void registerCallback( SomeJavascriptFunction func ) { ... }

我可以从Javascript中调用:

myapplet.registerCallback(function(){ alert("called back"); });

所以我可以在之后的代码中调用这个函数:

func.call( ... );

有类似这样的东西吗?我该如何实现?

目前,我的想法是创建一些JavaScript来处理这个回调机制,而不是从小程序中处理。

3个回答

4
我知道这是一个非常古老的问题,但是在我搜索其他内容时它在排名第二,并且我认为下面的内容可能会对其他发现此问题的人有所帮助。
最近,我做了类似的事情,其中一个Java小程序需要在完成任务后回调JavaScript,在成功或错误时调用不同的函数。随着最近的趋势,我的需求是调用作为参数传递给其他函数的匿名函数。这是客户端的javascript代码:
applet.DoProcessing({
    success: function(param) {
        alert('Success: ' + param);
    },
    error: function(param) {
        alert('Failed: ' + param);
    }
});

如其他答案所述,Java只能通过名称调用JavaScript方法。这意味着您需要一个全局回调方法,该方法可以根据需要调用其他方法:

function ProcessingCallback(isSuccessful, cbParam, jsObject) {
    if (isSuccessful && jsObject.success)
        jsObject.success(cbParam);
    else if (!isSuccessful && jsObject.error)
        jsObject.error(cbParam);
}

这个函数直接从Java小程序里被调用:

public void DoProcessing(final Object callbacks) {
   //do processing....


   JSObject w = JSObject.getWindow(this);
   //Call our named callback, note how we pass the callbacks parameter straight
   //back out again - it will be unchanged in javascript.
   w.call("ProcessingCallback", new Object[]{successful, output, callbacks});
}

如果您希望将参数对象的引用保持无限期,以便在需要时将其用作某种注册回调而不是可抛弃回调等,则可以这样做。

在我们的情况下,处理可能会非常耗时,因此我们实际上会启动另一个线程-回调在这里仍然有效:

public void DoProcessing(final Object callbacks) {
    //hold a reference for use in the thread
    final Applet app = this;

    //Create a new Thread object to run our request asynchronously
    //so we can return back to single threaded javascript immediately
    Thread async = new Thread() {
        //Thread objects need a run method
        public void run() {
            //do processing....


            JSObject w = JSObject.getWindow(app);
            //Call our named callback, note how we pass the callbacks parameter
            //straight back out again - it will be unchanged in javascript.
            w.call("ProcessingCallback", new Object[]{successful, output, callbacks});
        }
    }
    //start the thread
    async.start();
}

2

我是一个全新的Java <-> JavaScript通信的初学者,本周计划探索它。这是个好机会... :-)

经过一些测试,似乎你无法将JS函数传递给Java小程序。除非我做错了什么...

我尝试过:

function CallJava()
{
  document.Applet.Call("Does it work?");
  document.Applet.Call(function () { alert("It works!"); });
  document.Applet.Call(DoSomething); // A simple parameterless JS function
  document.Applet.Call(window.location);
}
function DumbTest(message, value)
{
  alert("This is a dumb test with a message:\n" + message + "\n" + value);
}

“Call”被定义为:

public void Call(String message)
{
  JSObject win = (JSObject) JSObject.getWindow(this);
  String[] arguments = { "Call with String", message };
  win.call("DumbTest", arguments);
}

public void Call(JSObject jso)
{
  JSObject win = (JSObject) JSObject.getWindow(this);
  String[] arguments = { "Call with JSObject", jso.toString() };
  win.call("DumbTest", arguments);
}

当我传递一个JS函数时(在所有FF3测试中),我在Java端得到null。
请注意,以下Java程序允许显示DumberTest函数的JS代码!
public int Do()
{
  JSObject win = (JSObject) JSObject.getWindow(this);
  JSObject doc = (JSObject) win.getMember("document");
  JSObject fun = (JSObject) win.getMember("DumberTest");
  JSObject loc = (JSObject) doc.getMember("location");
  String href = (String) loc.getMember("href");
  String[] arguments = { href, fun.toString() };
  win.call("DumbTest", arguments);
  return fun.toString().length();
}

简洁明了:我创建了一个JS函数:

function RegisterCallback(cbFunction)
{
  var callback = cbFunction.toString(); // We get JS code
  var callbackName = /^function (\w+)\(/.exec(callback);
  document.Applet.RegisterCallback(callbackName[1]);
}

我从toString的结果中提取JS函数的名称,并将其传递给Java小程序。我认为我们无法处理匿名函数,因为Java通过名称调用JS函数。

Java方面:

String callbackFunction;
public void RegisterCallback(String functionName)
{
  callbackFunction = functionName;
}
void UseCallbackFunction()
{
    if (callbackFunction == null) return;
    JSObject win = (JSObject) JSObject.getWindow(this);
    win.call(callbackFunction, null);
}

似乎你只能通过名称将函数传递给Java,因此你需要创建一个包装小程序的门面对象,该对象将接受函数引用并为它们提供临时名称。 - w00t

1

win.eval() 将调用预定义的javascript。

String callbackFunction;
public void RegisterCallback(String functionName)
{
  callbackFunction = functionName;
}
void UseCallbackFunction()
{
    if (callbackFunction == null) return;
    JSObject win = (JSObject) JSObject.getWindow(this);
    win.eval(callbackFunction);
}

eval比call更通用,因此在这个特定任务中效率较低,并且传递参数给JS函数更复杂。 - PhiLho

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