Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android WebView JavaScript callback to original View

I am writing an android app in which i insert javascript code in a webview and then the javascript replies by calling a java method specified with webview.addJavascriptInterface.

The problem is that the javascript-callback is running in another thread than the original view from which i started the process. Because of that i cant access the original view.

How can i access the original view?

I am using api level 7.

Here are the important code fragments:

JavaScript call:

webview.addJavascriptInterface(this, "ACall");
webview.loadUrl("javascript: ACall.update();");

Callback:

public void update() {
    TextView tv = (TextView) findViewById(R.id.tv);
    Log.v("test", "test");
    tv.setText("test");
}

And the stacktrace:

Uncaught handler: thread WebViewCoreThread exiting due to uncaught exception
ndroid.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
at android.view.ViewRoot.checkThread(ViewRoot.java:2706)
at android.view.ViewRoot.requestLayout(ViewRoot.java:560)
at android.view.View.requestLayout(View.java:7918)
at android.view.View.requestLayout(View.java:7918)
at android.view.View.requestLayout(View.java:7918)
at android.view.View.requestLayout(View.java:7918)
at android.view.View.requestLayout(View.java:7918)
at android.widget.TextView.checkForRelayout(TextView.java:5380)
at android.widget.TextView.setText(TextView.java:2684)
at android.widget.TextView.setText(TextView.java:2552)
at android.widget.TextView.setText(TextView.java:2527)
at shylux.android.GameActivity.update(GameActivity.java:53)
at android.webkit.BrowserFrame.stringByEvaluatingJavaScriptFromString(Native Method)
at android.webkit.BrowserFrame.stringByEvaluatingJavaScriptFromString(Native Method)
at android.webkit.BrowserFrame.loadUrl(BrowserFrame.java:149)
at android.webkit.WebViewCore.loadUrl(WebViewCore.java:1449)
at android.webkit.WebViewCore.access$1400(WebViewCore.java:48)
at android.webkit.WebViewCore$EventHub$1.handleMessage(WebViewCore.java:890)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:123)
at android.webkit.WebViewCore$WebCoreThread.run(WebViewCore.java:611)
at java.lang.Thread.run(Thread.java:1096)

//////////////// Current solution:

This is my current solution. I think there have to be a better way. This requires a lot of work if you want to do different tasks.

public void update() {
    tv.post(new UpdateTask());
}

private class UpdateTask implements Runnable {
    public void run() {
        tv.setText("test");
    }
}
like image 383
Shylux Avatar asked May 25 '12 14:05

Shylux


2 Answers

Thanks, I had a similar problem. The solution with runOnUiThread was surprisingly simple.

You can not update the UI of the activity from outside the thread in which it was originally created. runOnUiThread() method is used for doing UI changes.

        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                button.setBackgroundResource(R.drawable.practice_ri_wrong_3);
            }
        });
like image 99
user1471865 Avatar answered Sep 21 '22 12:09

user1471865


runOnUiThread is your friend. Just cook up a Runnable that makes the changes you need to your view, and pass it to runOnUiThread. The painless threading article suggests some other options you might consider (if you don't have a handle on the activity, then tv.post might be a goer).

like image 38
Iain Avatar answered Sep 22 '22 12:09

Iain