标题似乎有点含糊,但我想不出另一个,所以希望我能阐明我的问题:
我正在使用Android WebView和JavascriptInterface。从我的应用程序(Java)到WebView(JavaScript)的通信是这样完成的:
webview.loadUrl("javascript:function()");
这是一个异步调用,此后应由JavaBridge-Thread处理。
另一种方法(将Javascript转换为Java)可以通过从我的Javascript代码调用JavascriptInterface
mainInterface
来工作。我可以在JavascriptInterface中调用用@JavascriptInterface
声明的Java方法。该调用也由JavaBridge-Thread执行。
在详细介绍之前,这里是重要的代码:
ModelActivity.java
public boolean loadPropertyIntoWebview(final String element, final String property, final String value){
final int requestId = jsCallIndex.incrementAndGet();
webview.loadUrl("javascript:setProperty('"+element+"', '"+property.toLowerCase()+"', '"+value+"', "+requestId+")");
return waitForJsReturnValue(requestId, 1000);
}
private boolean waitForJsReturnValue(int index, int timeout){
long start = System.currentTimeMillis();
while(true){
long elapsed = System.currentTimeMillis() - start;
if(elapsed > timeout){
System.out.println("JS RESPONSE TIMEOUT");
break;
}
synchronized (jsReturnValueLock) {
String value = jsReturnValues.remove(index);
if(value != null){
if(value.toLowerCase().equals("true")){
return true;
}else{
System.out.println("JS BAD RESPONSE");
return false;
}
}
long toWait = timeout - (System.currentTimeMillis() - start);
if (toWait > 0)
try {
System.out.println("WAIT NOW FOR "+toWait+" ms on index "+index);
jsReturnValueLock.wait(toWait);
} catch (InterruptedException e) {
break;
}
else{
System.out.println("JS RESPONSE TIMEOUT");
break;
}
}
}
return false;
}
public void processJsReturnValue(int index, String value){
System.out.println("RECEIVED ANSWER "+value+" for index "+index+" WAIT FOR UNLOCK");
synchronized (jsReturnValueLock) {
System.out.println("UNLOCKED FOR INDEX "+index);
jsReturnValues.put(index, value);
jsReturnValueLock.notifyAll();
}
}
JavascriptInterface.java
@JavascriptInterface
public void onClick(String elementId, String property, String value){
final String[] info = elementId.split("_");
dbHandler.addOrUpdateOutVariable(Integer.parseInt(info[0]), Integer.parseInt(info[1]), property, value);
((ModelActivity)context).runOnUiThread(new Runnable() {
@Override
public void run() {
actionManager.fireClickEvent(Integer.valueOf(info[0]), Integer.valueOf(info[1]));
}
});
}
@JavascriptInterface
public void processJsReturnValue(String index, String value){
try{
((ModelActivity)context).processJsReturnValue(Integer.parseInt(index), value);
}catch(NumberFormatException e){
e.printStackTrace();
}
}
我基本上想做的是从我的JavaScript函数
setProperty()
(ModelActivity-> loadPropertyIntoWebview)中获取一个返回值。在初始化期间,从主线程多次调用
loadPropertyIntoWebview()
方法,并且始终通过这两个processJsReturnValue()
函数从JavaBridge-Thread接收答案。另一种情况是行不通的,当用户按下我的Web View 中的按钮并调用
onClick(String elementId, String property, String value)
在我的JavascriptInterface中。函数调用
actionManager.fireClickEvent(Integer.valueOf(info[0]), Integer.valueOf(info[1]));
经历了几个我无法详细解释的类和函数,但在最后一个实例中它将调用
loadPropertyIntoWebview(final String element, final String property, final String value)
。该调用也来自主线程,因为我在onClick函数中明确表示了这一点:
((ModelActivity)context).runOnUiThread(new Runnable() {
@Override
public void run() {
actionManager.fireClickEvent(Integer.valueOf(info[0]), Integer.valueOf(info[1]));
}
});
调试显示以下内容:
在初始化过程中和调用后
webview.loadUrl("javascript:setProperty('"+element+"', '"+property.toLowerCase()+"', '"+value+"', "+requestId+")");
JavaBridge-Thread立即返回
processJsReturnValue()
。当通过用户调用时,它不会那样做。然后直到我的超时while(true)循环完成主线程后,它才会去那里。
我希望整个过程不要太困惑,并且有人可以理解我的问题,甚至对这里发生的问题有一个想法。
最佳答案
尝试将onClick和processJsReturnValue分离为两个不同的JavascriptInterface类,创建它们的实例并独立注册。不确定,但似乎现在他们互相封锁了。
关于java - Android/Java多线程-线程直到主线程完成工作才继续,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30318453/