Название может показаться нечетким, но я не могу думать о другом, поэтому я надеюсь, что смогу устранить проблему:Андроид/Java Многопоточность - нить не продолжается до тех пор, пока основная нить не выполнит свою работу
Я использую Android WebView и JavascriptInterface. Сообщение от моего приложения (Java) в направлении WebView (JavaScript) выполняется следующим образом:
webview.loadUrl("javascript:function()");
Это асинхронный вызов и должны быть обработаны после по JavaBridge-Thread.
Другой способ (Javascript к Java) работает bei, вызывающий мой JavascriptInterface mainInterface
из моего кода Javascript. Я могу вызвать методы Java, объявленные с @JavascriptInterface
в моем JavascriptInterface. Этот вызов также выполняется 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()
вызывается несколько раз из Main-Thread и всегда получает ответ от JavaBridge-Thread через обе функции processJsReturnValue()
.
Другой случай, который не будет работать, когда пользователь нажимает кнопку в моей WebView и вызывает
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]));
}
});
Debugging показал следующее:
Во initilization и после вызова
webview.loadUrl("javascript:setProperty('"+element+"', '"+property.toLowerCase()+"', '"+value+"', "+requestId+")");
JavaBridge-Thread немедленно возвращает в processJsReturnValue()
.
При вызове через пользователя он этого не сделает. Тогда он не пойдет туда до тех пор, пока основной поток не будет выполнен с моим тайм-аутом while (true).
Надеюсь, что все это не слишком смущает, и кто-то понимает мою проблему и даже имеет представление о том, что здесь происходит не так.
Как loadPropertyIntoWebview приходит из actionManager.fireClickEvent? Похоже, что есть решение того, что вы просите, но я не понимаю, какой код обрабатывается обоими потоками (Main и JavaBridge) и почему? –