2015-05-19 3 views
2

Название может показаться нечетким, но я не могу думать о другом, поэтому я надеюсь, что смогу устранить проблему:Андроид/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).

Надеюсь, что все это не слишком смущает, и кто-то понимает мою проблему и даже имеет представление о том, что здесь происходит не так.

+0

Как loadPropertyIntoWebview приходит из actionManager.fireClickEvent? Похоже, что есть решение того, что вы просите, но я не понимаю, какой код обрабатывается обоими потоками (Main и JavaBridge) и почему? –

ответ

0

Попробуйте отделить onClick и processJsReturnValue как два разных класса JavascriptInterface, создать их экземпляры и зарегистрировать их независимо. Не уверен, но похоже, что теперь они блокируют друг друга.

+0

Это похоже на то, что это может сработать. К сожалению, я только что собрался на встречу, где мы решили, что нам не обязательно нужно возвращаемое значение. Но я буду помнить об этом, если нам понадобится возвратное значение в любом другом месте. Я бы даже попробовал это, тем не менее, потому что я хочу знать, решит ли это мою проблему. – Mazen

Смежные вопросы