1

By using Android Studio, I need to design a mobile application that reads data from the website

http://sspapi-dev.samsungrs.com/health

and refreshes the data every minute. The problem I am facing is that AsyncTask in Android can be executed only once, so the next time I try to refresh the page and read data again from the website I am getting the following error message.

2018-12-03 14:48:21.308 5065-5065/com.samsung.asynctaskexample E/AndroidRuntime: FATAL EXCEPTION: main Process: com.samsung.asynctaskexample, PID: 5065 java.lang.IllegalStateException: Cannot execute task: the task has already been executed (a task can be executed only once) at android.os.AsyncTask.executeOnExecutor(AsyncTask.java:605) at android.os.AsyncTask.execute(AsyncTask.java:560) at com.samsung.asynctaskexample.MainActivity.updateHTML(MainActivity.java:45) at com.samsung.asynctaskexample.MainActivity.access$000(MainActivity.java:10) at com.samsung.asynctaskexample.MainActivity$1$1.run(MainActivity.java:37) at android.os.Handler.handleCallback(Handler.java:751) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:154) at android.app.ActivityThread.main(ActivityThread.java:6682) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1520) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1410)

What are the different ways that are available to fix this error message? Here is my code.

MainActivity.java

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;

import java.util.Timer;
import java.util.TimerTask;

public class MainActivity extends AppCompatActivity implements AsyncResponse {
    GetMethodDemo asyncTask = new GetMethodDemo();
    TextView t1;
    String website = "http://sspapi-dev.samsungrs.com/health";

    private Timer autoUpdate;
    int refresh_interval = 60000;

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

        t1 = findViewById(R.id.textview1);

        asyncTask.delegate = this;
    }

    @Override
    public void onResume() {
        super.onResume();
        autoUpdate = new Timer();
        autoUpdate.schedule(new TimerTask() {
            @Override
            public void run() {
                runOnUiThread(new Runnable() {
                    public void run() {
                        updateHTML();
                    }
                });
            }
        }, 0, refresh_interval);
    }

    private void updateHTML() {
        asyncTask.execute(website);
    }

    @Override
    public void onPause() {
        autoUpdate.cancel();
        super.onPause();
    }

    @Override
    public void processFinish(String output){
        t1.setText(output);
    }
}

JsonHelper.java

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

public class JsonHelper{

    HttpURLConnection connection;
    String data;

    public String getdatafromurl(String url){
        try{
            URL url1 = new URL(url);

            connection = (HttpURLConnection) url1.openConnection();
            connection.connect();
            InputStream inputStream = connection.getInputStream();

            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
            String line = "";
            StringBuffer buffer = new StringBuffer();

            while ((line = reader.readLine()) != null) {
                buffer.append(line);
            }
            String result = buffer.toString();
            return result;
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return data;
    }
}

GetMethodDemo.java

import android.os.AsyncTask;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

public class GetMethodDemo extends AsyncTask<String, Void, String> {
    public AsyncResponse delegate = null;
    String server_response;

    @Override
    protected String doInBackground(String... strings) {

        URL url;
        HttpURLConnection urlConnection = null;

        try {
            url = new URL(strings[0]);
            urlConnection = (HttpURLConnection) url.openConnection();

            int responseCode = urlConnection.getResponseCode();

            if(responseCode == HttpURLConnection.HTTP_OK){
                server_response = readStream(urlConnection.getInputStream());
            }

            JsonHelper jsonhelper = new JsonHelper();
            String data = jsonhelper.getdatafromurl(strings[0]);

            return data;

        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return null;
    }

    @Override
    protected void onPostExecute(String s) {
        super.onPostExecute(s);
        delegate.processFinish(server_response);
    }

// Converting InputStream to String

    private String readStream(InputStream in) {
        BufferedReader reader = null;
        StringBuffer response = new StringBuffer();
        try {
            reader = new BufferedReader(new InputStreamReader(in));
            String line = "";
            while ((line = reader.readLine()) != null) {
                response.append(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return response.toString();
    }
}

AsyncResponse.java

public interface AsyncResponse {
    void processFinish(String output);
}

By the way, making use of

while(true) {
            asyncTask.execute(website);

            try
            {
                Thread.sleep(refresh_interval);
            }
            catch(InterruptedException ex)
            {
                break;
            }
        }

which I had first tried out initially, seems to be a bad idea since Thread.sleep function interferes with the performance of the other Android applications and even the overall Android operating system. I found out that making use of Timer in the way that I had described above is a good substitute for it.

Just I need to find out what changes are possible that I need to make to the code in order to read data from any given fixed website more than once, for example, to refresh at certain interval of period of time.

Phantômaxx
  • 37,901
  • 21
  • 84
  • 115
V. Raman
  • 211
  • 1
  • 4
  • 17
  • 1
    This is the most unusual implementation I've seen for AsyncTasks. What guide are you following??? – Zun Dec 03 '18 at 09:39
  • 1
    looks like you have to create a new instance of your AsyncTask before executing it – Vladyslav Matviienko Dec 03 '18 at 09:50
  • Sorry that it took some time for me to find out that link. What is unusual about it? By the way, what is the usual way to implement it? Guides that I am following are: https://stackoverflow.com/questions/8654876/http-get-using-android-httpurlconnection and https://www.mytrendin.com/fetch-json-data-using-asynctask-restful-api-display-recyclerview-android/. – V. Raman Dec 03 '18 at 10:26
  • `Context context;` as a global variable in `MainActivity` class extending `AppCompatActivity` class and implementing `AsyncResponse` interface, `context = this;` in `onCreate(Bundle savedInstanceState)` function and `private void updateHTML() {` `GetMethodDemo asyncTask = new GetMethodDemo();` `asyncTask.delegate = context;` `asyncTask.execute(website);` `}` in `updateHTML()` function seems to resolve this issue for me. – V. Raman Dec 07 '18 at 07:01

1 Answers1

2

The easiest thing you can do is create a different GetMethodDemo instance for each call to the server. To do so, you need to remove the asyncTask field from your activity class and change your updateHTML() method to something that looks like this:

private void updateHTML() {
    GetMethodDemo asyncTask = new GetMethodDemo();
    asyncTask.execute(website);
}

I just want to mention, that there are other alternatives to using timers and async tasks to achieve what you are aiming for. You could use something like WorkManager + Worker, RxJava, etc. I advice you to take a look at some of those after getting your code to work.

Danail Alexiev
  • 7,624
  • 3
  • 20
  • 28