Как зарегистрировать обратный вызов JavaScript в Java-апплете?
Я разрабатываю невидимый Java-апплет, который будет полностью управляться JavaScript.
Я могу легко вызвать методы Java-апплета, и я могу вызвать методы JavaScript из апплета с помощью netscape.javascript.JSObject.getWindow(this).call()
.
Но чтобы зарегистрировать обратный вызов JavaScript в апплете, я предполагаю, что мне понадобится какой-либо объект функции JavaScript.
Я хотел бы сделать:
public void registerCallback( SomeJavascriptFunction func ) { ... }
Что я могу вызвать из Javascript:
myapplet.registerCallback(function(){ alert("called back"); });
Поэтому я мог бы вызвать эту функцию в более позднем коде:
func.call( ... );
Есть ли что-то подобное? Как я могу это сделать?
Теперь я собираюсь создать Javascript для обработки этого механизма обратного вызова вместо этого из апплета.
Ответы
Ответ 1
Я новичок в обмене 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 (is) определяется как:
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.
Обратите внимание, что следующая процедура Java позволяет отображать JS-код функции DumberTest!
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]);
}
Я извлекаю имя функции JS из результата toString и передаю его в 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);
}
Ответ 2
Я понимаю, что это действительно старый вопрос, но он занимает второе место в одном из моих поисков чего-то еще, и я думаю, что ниже может помочь кто-то другой, который найдет это.
Недавно я сделал что-то подобное, когда 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});
}
Вы можете удерживать ссылку на объект параметра, передаваемый неограниченно, если вы хотите использовать его как некоторая форма зарегистрированного обратного вызова, а не одноразовая, если это необходимо и т.д.
В нашем случае обработка может быть временной intenstive, поэтому мы фактически разворачиваем другой поток - здесь также работают обратные вызовы:
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();
}
Ответ 3
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);
}