简体   繁体   中英

Android Asynctask update UI and computation

I am a beginner at android/java development and I have just started learning about asynctask. I am trying to create an application that counts up (updating the ui thread with each incremental count) with a variable delay, and I am not sure how to pass the values into the asynctask, or even get it to work.

/*I have an editText (I used editText on purpose) named log, which is supposed 
to be the output of the operation. 
count is the number of counting up that I want the log to display. 
time is the sleep delay I wish to set inbetween printing each number.*/

    public class backgroundsend extends AsyncTask<String, Integer, String>{
    @Override
    protected String doInBackground(String... params) {
//and I want i to be the current count of the number to be displayed.
       for (int i=1; i<count+1; i++){
            try {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        log.setText(log.getText() +i);
                    }
                });
                Thread.sleep(time);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        return null;
    }
    @Override
    protected void onProgressUpdate(Integer... values) {
    }
    @Override
    protected void onPostExecute(String result){
        log.setText(log.getText() + "Operation Ended \n\n");
    }
}

Now this code does not compile properly because it wants i to be a final variable, and I don't know how to make the i in for loop into a final variable, if possible. I tried using a dummy variable and adding +1 every loop run and it still doesn't work. Additionally, when I tried to use the for loop/asynctask without the i value (a constant value) it would run but the ui thread would still hang like normal on large values. Can somebody give me insight as to what I am doing wrong, and how I should correct it? Thank you.

Couple problems.

  1. Don't use runOnUiThread() anywhere in AsyncTask ...it defeats the purpose. All functions of AsyncTask run on the UI Thread except for doInBackground() so the idea is to do heavy work in doInBackground() and update UI in the other functions.
  2. You have onPostExecute() expecting a String but you are returning null from doInBackground() and that function passes its result (if there should be one) to onPostExecute()
  3. You can pass updates to onProgressUpdate() by calling publishProgress() in doInBackground()

To fix this you could do something like

    protected String doInBackground(String... params) 
    {
       for (int i=1; i<count+1; i++)
       {
            publishProgress(i);   update UI in onProgressUpdate()
            Thread.sleep(time);
        } 
     }
        return "Operation Ended \n\n";
    }

    @Override
    protected void onPostExecute(String result){
       log.setText(log.getText() + result);
    }
    @Override
    protected void onProgressUpdate(Integer... values) 
    {
        // update UI here 
    }

I don't know how you are calling the task so I don't know what you are doing wrong there but you can do something like

backgroundsend myTask = new backgroundsend();  // can pass params to a constructor if needed
myTask.execute(...); // the ... is where you would put params to pass to doInBackground()

Thread.sleep() is a bad way to delay repetitions:

Why using System.Threading.Thread.Sleep() is a bad practice?

You can use a CountDownTimer:

Android CountDownTimer

but if I were you, I would post a delayed execution N-times since you already have an existing view (your text field):

// number of repetitions
private static final int REPETITIONS = 5;
// delay in mills
private static final int DELAY = 100;
// count
private int count;
final Runnable countingRunnable = new Runnable() {
    @Override
    public void run() {
        if (count < REPETITIONS)  {
            count = count + 1;
            log.postDelayed(countingRunnable, DELAY);
        }
        else {
            // TODO call a method, notify a listener or whatnot your updates are over
        }
    }
};
...
// then in your place where you want to trigger the counting
log.postDelayed(countingRunnable, DELAY);
...
// and in `Activity|Fragment.onDestroy()` ensure to remove the callbacks
log.removeCallbacks(countingRunnable);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM