2

I inject JavaScript interface to my WebView, and once I get to my native methods that I defined in the JavaScript, if freezes the WebViewuntil I return a value. For example:

In this example the WebView is stuck for the 8 seconds. I also double-checked that it is not the main thread, and it is indeed NOT the main thread, so I just don't see a reason why would it freeze the WebView.

myWebView.addJavascriptInterface( new WebViewHandler.JavaScriptInterface(), "webCallHandler" );

public class JavaScriptInterface
{
    @JavascriptInterface
    public String jsToAndroidNativeFunc(String Data)
    {

        Callable<String> task = new Callable<String>() {
            @Override
            public String call() throws Exception {
                try {
                    if( Looper.getMainLooper() == Looper.myLooper() )
                        Log.d("TAG","Main Thread");
                    else
                        Log.d("TAG","Not Main Thread");
                    TimeUnit.SECONDS.sleep(8); // the webview is now stuck during these 8 seconds
                    return "123";
                }
                catch (InterruptedException e) {
                    throw new IllegalStateException("task interrupted", e);
                }
            }
        };

        ExecutorService executor = Executors.newFixedThreadPool(1);
        Future<String> future = executor.submit(task);

        try {
            return future.get();
        }
        catch (InterruptedException e) {
            e.printStackTrace();
            return "111";
        } catch (ExecutionException e) {
            e.printStackTrace();
            return "111";
        }
    }
}
Ahmer Afzal
  • 501
  • 2
  • 11
  • 24
BVtp
  • 2,308
  • 2
  • 29
  • 68

1 Answers1

0

Update

This code is invoked with the following javascript code:

var response = webCallHandler.jsToAndroidNativeFunc(request.data);

This is exactly what makes the UI freeze because javascript is single-threaded. We must make asynchronous invocations with callbacks. Just like Ajax.

Original answer

I don't know the js android interface. What I do know is that your function is waiting for an answer. I.e. Future.get() is a blocking function. Excerpt from the API:

Waits if necessary for the computation to complete, and then retrieves its result.

I suggest to make this jsToAndroidNativeFunc void and add some callback. Also, I suggest to define an executor outside of the method. E.g. at class or app level:

public class JavaScriptInterface
{

    private final ExecutorService EXECUTOR = Executors.newFixedThreadPool(1);

    @JavascriptInterface
    public void jsToAndroidNativeFunc(String Data, Callback callback)
    // I just made up the Callback class. There must be a way to do so with webview too.
    {

        Callable<String> task = new Callable<String>() {
            @Override
            public String call() throws Exception {
                try {
                    // ...
                    callback.call("123"); // no return, but call the js callback
                }
                catch (InterruptedException e) {
                    throw new IllegalStateException("task interrupted", e);
                }
            }
        };

        EXECUTOR.submit(task); // using the static executor
        // no Future, no return either. Js side will execute asynchronously.
    }
Community
  • 1
  • 1
Tamas Rev
  • 7,008
  • 5
  • 32
  • 49
  • Unfortunately this jsToAndroidNativeFunc has to return a response and cannot be void. The javascript I injected to the webview awaits for that response : `var response = webCallHandler.jsToAndroidNativeFunc(request.data);" ` – BVtp Apr 06 '17 at 09:42
  • At [this answer](http://stackoverflow.com/a/14145116/187808) they solve similar problem:Android webview + callback. On the other hand, it's this waiting js code that makes your app freeze. Bottom line: javascript is single-threaded. – Tamas Rev Apr 06 '17 at 09:52