如何在 Android 中等待异步 API?

How to wait for async APIs in Android?

android中,有很多async APIs比如WebView的evaluateJavascript,会Asynchronously在当前显示页面的上下文中求值JavaScript .通常,在调用 async API 之后,执行将继续执行后续语句,而无需任何等待。

但是在继续 successive statements 之前,我如何才能 等待 直到此调用完成执行。例如,

webview.evaluateJavascript("JS code", new ValueCallback<String> {
    public void onReceiveValue(String value) {
        //get JS return here
    }
});
//Remaining code

如何确保在 webview.evaluateJavascript 完成执行后执行剩余代码(即,其回调 onReceiveValue 已完成执行)。

编辑:更准确地说,我想要的是剩余的代码应该在 onReceiveValue 完成执行后执行。

当您必须等待代码执行时,一个简单的 class 可以使用的是 CountDownLatch。 您的问题的示例可以是:

public class AboutActivity extends Activity {
    private volatile CountDownLatch jsLatch = new CountDownLatch(1);
    private volatile String jsReceivedValue = null

    initWebView() {
        // webview init
        ...

        webview.evaluateJavascript("JS code", new ValueCallback<String> {
            public void onReceiveValue(String value) {
                //get JS return here
                jsReceivedValue = value
                jsLatch.countDown();
            }
        });
        try {
            // wait 60 seconds or assume there was some problem during the loading
            jsLatch.await(60, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            // thread interrupted or time elapsed
        }

        if (jsReceivedValue == null) {
            // show "problem during loading"
        } else {
            //Remaining code
        }   
    }
}

请注意,在主线程上等待代码执行可能会导致应用无响应。 您可以在使用简单线程时显示加载微调器来避免这种情况:

new Thread(new Runnable() {
    @Override
    public void run() {
        initWebView();
    }
}).start();

我通过使用 Java脚本界面找到了解决方法。这个想法是我们创建一个桥 class,其中包含一个将 javascript 执行结果作为输入的方法。那么我们就可以得到Java端的结果了。此方法之所以有效,是因为桥接方法由 Java 脚本代码调用,该脚本代码在另一个线程上 运行。我们只需要在 UI 线程上等待几毫秒,结果就在这里。以下代码为例:

class Bridge {

    public String result = null;

    @JavascriptInterface
    public void putJsResult(String result) {
        this.result = result;
    }

    public String getJsResult() {
        return this.result;
    }
}

Bridge bridge = new Bridge();
wv.addJavascriptInterface(bridge, "bridge");
webview.evaluateJavascript("bridge.putJsResult(func())", null);
Thread.sleep(100);
//Result is there
String result = bridge.getJsResult();