JavascriptInterface в Android WebView: множественные вызовы JS вызывают тупик - PullRequest
5 голосов
/ 02 ноября 2011

Это весь код Java, который я использовал. Я объясню более подробно ниже ...

public class Test7 extends Activity {
    //debug
    private final static String TAG = "JSInterface";

    private WebView wv;

    private class JSInterface {
        private WebView wv;

        // Variables to manage interfacing with JS
        private String returnValue;
        private boolean canReadReturnValue;
        private Lock lockOnJS;
        private Condition condVarOnJS;

        public JSInterface (WebView wv) {
            this.wv = wv;       
            this.canReadReturnValue = false;
            this.lockOnJS = new ReentrantLock();
            this.condVarOnJS = lockOnJS.newCondition();
        }

        public void setReturnValue(String ret) {
            lockOnJS.lock();
            returnValue = ret;
            canReadReturnValue = true;
            condVarOnJS.signal();
            lockOnJS.unlock();
            Log.d(TAG, "returnValue = " + returnValue);
        }

        public String getReturnValue() {
            Log.d(TAG, "enter in getReturnValue");
            lockOnJS.lock();
            while (!canReadReturnValue) {
                try {
                    Log.d(TAG, "get wait...");
                    condVarOnJS.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
            lockOnJS.unlock();
            Log.d(TAG, "returnValue: " + returnValue);
            return returnValue;
        }

        public String getNewString() {
            wv.loadUrl("javascript:JSInterface.setReturnValue(createNewString())");         
            return getReturnValue();
        }
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        wv = (WebView) findViewById(R.id.webView1);
        wv.getSettings().setJavaScriptEnabled(true);
        wv.addJavascriptInterface(new JSInterface(wv), "JSInterface");
        wv.loadUrl("file:///android_asset/prova7.html");
    }

    public void button1(View v) {
        wv.loadUrl("javascript:func('1')");
    }
}

И, кажется, работает нормально.

Вы видите, что у меня есть кнопка (которую мы можем вызвать button1 ), и, нажав на нее, она пытается выполнить метод JS, называемый func () .

public void button1(View v) {
    wv.loadUrl("javascript:func('1')");
}

Внутри этого метода JS мне нужно вызвать другой метод Java. Это код:

function func(id) {
    document.getElementById(id).innerHTML = JSInterface.getNewString();
}

Мне нужно вернуть результат JSInterface.getNewString () в переменную innerHTML.

Код JSInterface.getNewString () таков:

public String getNewString() {
    wv.loadUrl("javascript:JSInterface.setReturnValue(createNewString())");         
    return getReturnValue();
}

Вы видите, что я использую методы setReturnValue и getReturnValue для возврата значения, возвращенного другим методом JS. Это код:

function createNewString() {
    return "my New String";
}

Проблема в том, что когда я пытаюсь установить returnValue, функция createNewString никогда не выполняется! Если я добавлю строку console.log (), мой logCat ничего не отобразит!

Я не могу понять, почему это происходит.

Ответы [ 3 ]

2 голосов
/ 25 января 2012

Все javascript и ваши методы JSInterface, вызываемые из javascript , выполняются в одном потоке в Android WebView.Поэтому, пока вы ожидаете в condVarOnJS.await(), никакой javascript не может быть выполнен, просто потому что он выполняется в одном и том же потоке.

Более того, все экземпляры webview в вашем приложении совместно используют один и тот же поток javascript.

0 голосов
/ 08 ноября 2011

Я сделал ту функциональность, которую вы намеревались в этом коде, для меня вызывается createNewString (),

Я покажу код, который я использовал,

В Яве

   public String  videoPlay(){
        System.out.println("videoPlay");
        mWebView.loadUrl("javascript:window.demo.setReturnValue(createNewString())");
        return getReturnValue();}

public void setReturnValue(String test){
        rotValue=test;
        System.out.println(test);

    }
    public String getReturnValue(){
        System.out.println("get"+rotValue);
        return rotValue;
    }

в HTML,

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
   <script>
function inform(){
    alert('et');

   document.getElementById('myText').value=window.demo.videoPlay();
   alert('et');
 }
function createNewString() {
    return "my New String";
}
</script>
</head>
<body onload="init()">
<form>
<input type='text' id='myText' />
<input type="button" name="test" value="Click me" onclick="inform()">
</form>
</body>
</html> 

Вызваны функции getter и setter, а также установлены значения, но у меня есть выходной журнал как ..

11-08 19:18:17.155: INFO/System.out(847): videoPlay
11-08 19:18:17.165: INFO/System.out(847): getnull
11-08 19:18:17.875: INFO/System.out(847): my New String

videoPlay вызывается из JS, а createnewString () также вызывается из java в JS, но возвращает значение до его установки, потому что я не знаю, какова цель использовать блокировку, даже я пытался использовать блокировку, как вы делали для этого будет напечатано

 11-08 19:18:17.155: INFO/System.out(847): videoPlay
    11-08 19:18:17.165: INFO/System.out(847): getnull

с помощью блокировки также функция обратного вызова работает неправильно, вам нужно работать с блокировками.

0 голосов
/ 08 ноября 2011

В Internet Explorer я обнаружил ту же проблему. Вы можете использовать setTimeout так:

function func(id) {
    setTimeout(
        function(){
            document.getElementById(id).innerHTML = JSInterface.getNewString();
        }, 
        500);
} 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...