0

So I have a Webview and a JavascriptInterface attached to it, how can I show/hide a dialog when a method in the interface is triggered and a request is made to another URL?

I have a game in JavaScript user plays it and when the game is over the score is sent to the interface and if the score is greater than 200 I want to send a request to another server and wanna show/hide dialog during it's processing.

I get this exception: CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

GameActivity.java

Handler mHandler = new Handler(Looper.getMainLooper()); // initialized in onCreate()

private void setWebview(int level) {
    WebView webView = findViewById(R.id.webView);
    webView.setWebChromeClient(new WebChromeClient());
    webView.clearCache(true);
    webView.getSettings().setJavaScriptEnabled(true);
    webView.addJavascriptInterface(new WebViewJavaScriptInterface(this, mHandler), "app");
    webView.getSettings().setLoadWithOverviewMode(true);
    webView.getSettings().setUseWideViewPort(true);
    webView.loadUrl(Helper.GAME_URL + level);
}

private class WebViewJavaScriptInterface {
    private Context context;

    private Handler mHandler;

    WebViewJavaScriptInterface(Context context, Handler mHandler) {
        this.context = context;
        this.mHandler = mHandler;
    }

    @JavascriptInterface
    public void tellScore(int score) {
        if (score >= 200) {
            showProgressDialog(); // No error here

            RequestBody roundBody = new MultipartBody.Builder()
                    .setType(MultipartBody.FORM)
                    .addFormDataPart("uid", getUid())
                    .build();

            Request roundRequest = new Request.Builder()
                    .cacheControl(CacheControl.FORCE_NETWORK)
                    .url(Helper.POST_URL)
                    .post(roundBody)
                    .build();

            client.newCall(roundRequest).enqueue(new Callback() {
                @Override
                public void onFailure(@NonNull Call call, @NonNull IOException e) {
                    e.printStackTrace();
                    showSnackbarAndFinish();
                }

                @Override
                public void onResponse(@NonNull Call call, @NonNull final Response roundResponse) {
                    mHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            if (roundResponse.code() == 200) {
                                String jsonData = "";
                                try {
                                    jsonData = roundResponse.body().string();
                                } catch (IOException e) {
                                    e.printStackTrace();
                                }

                                try {
                                    final JSONObject jObject = new JSONObject(jsonData);

                                    if (jObject.getBoolean("error")) {
                                        try {
                                            hideProgressDialog(); // <-- error here
                                        } catch (JSONException e) {
                                            e.printStackTrace();
                                        }
                                    } else {
                                        try {
                                            scoreGuide.setText("Score 200 points to earn " + (Integer.parseInt(jObject.getJSONObject("message").getString("current_level")) / 10d));
                                            hideProgressDialog(); // <-- error here
                                        } catch (JSONException e) {
                                            e.printStackTrace();
                                        }
                                    }
                                } catch (Exception e) {
                                    e.printStackTrace();
                                }
                            } else {
                                showSnackbarAndFinish();
                            }

                        }
                    });
                }
            });
        }
    }
}
Phantômaxx
  • 37,901
  • 21
  • 84
  • 115

1 Answers1

0

You should only touch GUI from the MainThread, as the error already states. To join the MainThread use Handler handler = new Handler(Looper.getMainLooper()). Then use handler's post or postDelayed methods to run your methods from the MainThread. Hope this helps.

Edit: As Mark Keen correctly pointed out, this is already done. There are other ways to run methods from the UI thread, see https://stackoverflow.com/a/13974916/10107980 for more information. Although I don't know why your code doesn't work in the first place.

pF1Tz
  • 1
  • 2
  • that's already there, this is declared `Handler mHandler = new Handler(Looper.getMainLooper());` already, Look inside `onResponse` - `mHamdler.post()`. – Mark Jul 28 '18 at 09:37
  • tried with postDelayed() instead of post() same error – Devanshu Linux Jul 28 '18 at 09:43
  • Oh, guess I didn't read the code enough. There are other ways to run an action from the UI Thread, see: https://stackoverflow.com/a/13974916/10107980 – pF1Tz Jul 28 '18 at 09:43