why evaluateJavascript is getting iterated inside handler(Android)?

Tags: , , , ,



I want to evaluate a javascript in Webview Android as given below in the code. I want to evaluate it after 3 seconds. It works, it gets evaluated after 3 seconds but it(the code inside run()) keeps repeating after every 3 seconds in an infinite loop. I just want to evaluate it once after 3 seconds

                    int delay = 3000;
                    new Handler().postDelayed(new Runnable() {
                        @Override
                        public void run() {

                            Toast.makeText(MainActivity.this,"Reached",Toast.LENGTH_LONG).show();
                            final String js3 = "javascript:document.getElementsByClassName('icon')[0].click();";
                            view.evaluateJavascript(js3,null);
                        }
                    },delay);

MainActivity.java

public class MainActivity extends AppCompatActivity {

    //webview
    private WebView webView;
    private String uname,password;
    private int x=0;
    private  CountDownTimer timer;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        webView = (WebView) findViewById(R.id.webView);

       
        final String password = "Pass@123";
        final String username = "111111111";
        //url
        webView.getSettings().setJavaScriptEnabled(true);
        webView.getSettings().setDomStorageEnabled(true);
        webView.loadUrl("https://something.com/xyz/abc/student2020.html#");
        webView.setWebViewClient(new WebViewClient(){
            @Override
            public void onPageFinished(WebView view, String url) {
                super.onPageFinished(view, url);

                final String js = "javascript:" +
                        "document.getElementById('phone_1').value = '" + username + "';"  +
                        "document.getElementById('submit_1').click()";

                if (Build.VERSION.SDK_INT >= 19) {
                    view.evaluateJavascript(js,null);

                            final String js2 = "javascript:"+"document.getElementById('pass_2').value = '"+password+"';"
                                    + "document.getElementById('phone_2').value = '" + username + "';"
                                    + "javascript:document.getElementById('submit_2').click()";
                            view.evaluateJavascript(js2,null);
                            

                    int delay = 3000;
                    new Handler().postDelayed(new Runnable() {
                        @Override
                        public void run() {

                            Toast.makeText(MainActivity.this,"Reached",Toast.LENGTH_LONG).show();
                            final String js3 = "javascript:document.getElementsByClassName('icon')[0].click();";
                            view.evaluateJavascript(js3,null);
                        }
                    },delay);

                } else {
                    view.loadUrl(js);

                }
            }
        });

activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <WebView
        android:id="@+id/webView"
        android:layout_height="match_parent"
        android:layout_width="match_parent"/>

</RelativeLayout>

Answer

calling evaluateJavascript will make onPageFinished to be called further, in which you are setting, again, your Handler

simplest way to avoid this is introducing some boolean which will be flagged after evaluating JS and prevent second and further calls

private WebView webView;
private String uname,password;
private int x=0;
private  CountDownTimer timer;
private boolean jsExecuted = false;

in callback

        @Override
        public void onPageFinished(WebView view, String url) {
            super.onPageFinished(view, url);
            if (jsExecuted) return;
            jsExecuted = true
            // JS execution code
        }

btw. you have probably some bug in flow for <19, only first JS will be loaded/executed



Source: stackoverflow