Advertisement
Advertisement


AsyncTask Android example


Question

I was reading about AsyncTask, and I tried the simple program below. But it does not seem to work. How can I make it work?

public class AsyncTaskActivity extends Activity {

    Button btn;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        btn = (Button) findViewById(R.id.button1);
        btn.setOnClickListener((OnClickListener) this);
    }

    public void onClick(View view){
        new LongOperation().execute("");
    }

    private class LongOperation extends AsyncTask<String, Void, String> {
        @Override
        protected String doInBackground(String... params) {
            for(int i=0;i<5;i++) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            TextView txt = (TextView) findViewById(R.id.output);
            txt.setText("Executed");
            return null;
        }

        @Override
        protected void onPostExecute(String result) {
        }

        @Override
        protected void onPreExecute() {
        }

        @Override
        protected void onProgressUpdate(Void... values) {
        }
    }
}

I am just trying to change the label after 5 seconds in the background process.

This is my main.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="fill_parent"
              android:layout_height="fill_parent"
              android:orientation="vertical" >
    <ProgressBar
        android:id="@+id/progressBar"
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:indeterminate="false"
        android:max="10"
        android:padding="10dip">
    </ProgressBar>
    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Start Progress" >
    </Button>
    <TextView android:id="@+id/output"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Replace"/>
</LinearLayout>
2019/01/24
1
684
1/24/2019 2:05:59 PM

Accepted Answer

Ok, you are trying to access the GUI via another thread. This, in the main, is not good practice.

The AsyncTask executes everything in doInBackground() inside of another thread, which does not have access to the GUI where your views are.

preExecute() and postExecute() offer you access to the GUI before and after the heavy lifting occurs in this new thread, and you can even pass the result of the long operation to postExecute() to then show any results of processing.

See these lines where you are later updating your TextView:

TextView txt = findViewById(R.id.output);
txt.setText("Executed");

Put them in onPostExecute().

You will then see your TextView text updated after the doInBackground completes.

I noticed that your onClick listener does not check to see which View has been selected. I find the easiest way to do this is via switch statements. I have a complete class edited below with all suggestions to save confusion.

import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.provider.Settings.System;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.view.View.OnClickListener;

public class AsyncTaskActivity extends Activity implements OnClickListener {

    Button btn;
    AsyncTask<?, ?, ?> runningTask;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        btn = findViewById(R.id.button1);

        // Because we implement OnClickListener, we only
        // have to pass "this" (much easier)
        btn.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        // Detect the view that was "clicked"
        switch (view.getId()) {
        case R.id.button1:
            if (runningTask != null)
                runningTask.cancel(true);
            runningTask = new LongOperation();
            runningTask.execute();
            break;
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // Cancel running task(s) to avoid memory leaks
        if (runningTask != null)
            runningTask.cancel(true);
    }

    private final class LongOperation extends AsyncTask<Void, Void, String> {

        @Override
        protected String doInBackground(Void... params) {
            for (int i = 0; i < 5; i++) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    // We were cancelled; stop sleeping!
                }
            }
            return "Executed";
        }

        @Override
        protected void onPostExecute(String result) {
            TextView txt = (TextView) findViewById(R.id.output);
            txt.setText("Executed"); // txt.setText(result);
            // You might want to change "executed" for the returned string
            // passed into onPostExecute(), but that is up to you
        }
    }
}
2019/11/25
704
11/25/2019 10:01:18 AM


I'm sure it is executing properly, but you're trying to change the UI elements in the background thread and that won't do.

Revise your call and AsyncTask as follows:

Calling Class

Note: I personally suggest using onPostExecute() wherever you execute your AsyncTask thread and not in the class that extends AsyncTask itself. I think it makes the code easier to read especially if you need the AsyncTask in multiple places handling the results slightly different.

new LongThread() {
    @Override public void onPostExecute(String result) {
        TextView txt = (TextView) findViewById(R.id.output);
        txt.setText(result);
    }
}.execute("");

LongThread class (extends AsyncTask):

@Override
protected String doInBackground(String... params) {
    for (int i = 0; i < 5; i++) {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    return "Executed";
}      
2019/06/03

Concept and code here

I have created a simple example for using AsyncTask of Android. It starts with onPreExecute(), doInBackground(), publishProgress() and finally onProgressUpdate().

In this, doInBackground() works as a background thread, while other works in the UI Thread. You can't access an UI element in doInBackground(). The sequence is the same as I have mentioned.

However, if you need to update any widget from doInBackground, you can publishProgress from doInBackground which will call onProgressUpdate to update your UI widget.

class TestAsync extends AsyncTask<Void, Integer, String> {
    String TAG = getClass().getSimpleName();

    protected void onPreExecute() {
        super.onPreExecute();
        Log.d(TAG + " PreExceute","On pre Exceute......");
    }

    protected String doInBackground(Void...arg0) {
        Log.d(TAG + " DoINBackGround", "On doInBackground...");

        for (int i=0; i<10; i++){
            Integer in = new Integer(i);
            publishProgress(i);
        }
        return "You are at PostExecute";
    }

    protected void onProgressUpdate(Integer...a) {
        super.onProgressUpdate(a);
        Log.d(TAG + " onProgressUpdate", "You are in progress update ... " + a[0]);
    }

    protected void onPostExecute(String result) {
        super.onPostExecute(result);
        Log.d(TAG + " onPostExecute", "" + result);
    }
}

Call it like this in your activity:

new TestAsync().execute();

Developer Reference Here

2019/11/25

Move these two lines:

TextView txt = (TextView) findViewById(R.id.output);
txt.setText("Executed");

out of your AsyncTask's doInBackground method and put them in the onPostExecute method. Your AsyncTask should look something like this:

private class LongOperation extends AsyncTask<String, Void, String> {

    @Override
    protected String doInBackground(String... params) {
        try {
            Thread.sleep(5000); // no need for a loop
        } catch (InterruptedException e) {
            Log.e("LongOperation", "Interrupted", e);
            return "Interrupted";
        }
        return "Executed";
    }      

    @Override
    protected void onPostExecute(String result) {               
        TextView txt = (TextView) findViewById(R.id.output);
        txt.setText(result);
    }
}
2012/03/12

Background / Theory

AsyncTask allows you to run a task on a background thread, while publishing results to the UI thread.

The user should always able to interact with the app so it is important to avoid blocking the main (UI) thread with tasks such as downloading content from the web.

This is why we use an AsyncTask.

It offers a straightforward interface by wrapping the UI thread message queue and handler that allow you to send and process runnable objects and messages from other threads.

Implementation

AsyncTask is a generic class. (It takes parameterized types in its constructor.)

It uses these three generic types:

Params - the type of the parameters sent to the task upon execution.

Progress - the type of the progress units published during the background computation.

Result - the type of the result of the background computation.

Not all types are always used by an asynchronous task. To mark a type as unused, simply use the type Void:

private class MyTask extends AsyncTask<Void, Void, Void> { ... }

These three parameters correspond to three primary functions you can override in AsyncTask:

  • doInBackground(Params...)
  • onProgressUpdate(Progress...)
  • onPostExecute(Result)

To execute AsyncTask

  • Call execute() with parameters to be sent to the background task.

What Happens

  1. On main/UI thread, onPreExecute() is called.

    • To initialize something in this thread. (E.g. show a progress bar on the user interface.)
  2. On a background thread, doInBackground(Params...) is called.

    • (Params were passed via execute.)
    • Where the long-running task should happen.
    • Must override at least doInBackground() to use AsyncTask.

    • Call publishProgress(Progress...) to update the user interface with a display of progress (e.g. UI animation or log text printed) while the background computation is still executing.

      • Causes onProgressUpdate() to be called.
  3. On the background thread a result is returned from doInBackground().

    • (This triggers the next step.)
  4. On main/UI thread, onPostExecute() is called with the returned result.

Examples

In both examples the "blocking task" is a download from the web.

  • Example A downloads an image and displays it in an ImageView, while
  • Example B downloads some files.

Example A

The doInBackground() method downloads the image and stores it in an object of type BitMap. The onPostExecute() method takes the bitmap and places it in the ImageView.

class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
    ImageView bitImage;

    public DownloadImageTask(ImageView bitImage) {
        this.bitImage = bitImage;
    }

    protected Bitmap doInBackground(String... urls) {
        String urldisplay = urls[0];
        Bitmap mBmp = null;
        try {
            InputStream in = new java.net.URL(urldisplay).openStream();
            mBmp = BitmapFactory.decodeStream(in);
        } catch (Exception e) {
            Log.e("Error", e.getMessage());
            e.printStackTrace();
        }
        return mBmp;
    }

    protected void onPostExecute(Bitmap result) {
        bitImage.setImageBitmap(result);
    }
}

Example B

 private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
     protected Long doInBackground(URL... urls) {
         int count = urls.length;
         long totalSize = 0;
         for (int i = 0; i < count; i++) {
             totalSize += Downloader.downloadFile(urls[i]);
             publishProgress((int) ((i / (float) count) * 100));
             // Escape early if cancel() is called
             if (isCancelled()) break;
         }
         return totalSize;
     }

     protected void onProgressUpdate(Integer... progress) {
         setProgressPercent(progress[0]);
     }

     protected void onPostExecute(Long result) {
         showDialog("Downloaded " + result + " bytes");
     }
 }

Example B execution

new DownloadFilesTask().execute(url1, url2, url3);
2019/07/05

How to memorize the parameters used in AsyncTask?

Don't

If you are new to AsyncTask then it is very common to get confused while writing an AsyncTask. The main culprits are the parameters used in the AsyncTask, i.e., AsyncTask<A, B, C>. Based on the A, B, C (arguments) signature of the methods differs which makes things even more confusing.

Keep it simple!

The key is don't memorize. If you can visualize what your task really needs to do then writing the AsyncTask with the correct signature at the first attempt would be a piece of cake. Just figure out what your Input, Progress, and Output are, and you will be good to go.

So what is an AsyncTask?

AsyncTask is a background task that runs in the background thread. It takes an Input, performs Progress and gives an Output.

I.e., AsyncTask<Input, Progress, Output>.

For example:

Enter image description here

What is the relationship with methods?

Between AsyncTask and doInBackground()

Enter image description here

doInBackground() and onPostExecute(),onProgressUpdate()` are also related

Enter image description here

How to write that in the code?

DownloadTask extends AsyncTask<String, Integer, String>{

    // Always same signature
    @Override
    public void onPreExecute()
    {}

    @Override
    public String doInbackGround(String... parameters)
    {
        // Download code
        int downloadPerc = // Calculate that
        publish(downloadPerc);

        return "Download Success";
    }

    @Override
    public void onPostExecute(String result)
    {
        super.onPostExecute(result);
    }

    @Override
    public void onProgressUpdate(Integer... parameters)
    {
        // Show in spinner, and access UI elements
    }

}

How will you run this Task?

new DownLoadTask().execute("Paradise.mp3");
2019/11/26

Source: https://stackoverflow.com/questions/9671546
Licensed under: CC-BY-SA with attribution
Not affiliated with: Stack Overflow
Email: [email protected]