Android:Thread

From Juneday education
Jump to: navigation, search

Everyone expects an app to be responsive (e. g. we expect an app to respond quickly to a click). If the app downloads a web page and we want to user to be able to click cancel we need to do two things at the same time. So we need to use threads. In this chapter we will give a very short introduction to threads in Android and give bit more detailed introduction to AsyncTask, which makes a developer's life a lot easier.

Videos

Channel: Android Threads

External videos

In the video turial Developing Android Apps, by Google, we recommend you watch the lesson "Background tasks".

Threads in Android

When your app starts Android creates one thread for you. This thread is called the main thread (or the GUI thread). This thread, as the name "GUI Thread" suggests, deals with the user interaction. If your app is busy downloading a web page, storing data to a database or some other task that takes time your app will be slow in responding to user interaction. Imagine how slow your app would feel like if the user clicks a download link of a 8GB ISO image and you can't cancel it. What would you do with such an app? Yes, most likely uninstall it. So, you better use threads.

Let's continue the example of downloading a web page. Let's now assume your a good Android citizen and do the downloadinng in a thread. When you're done you want to update the gui. Since Android's UI toolkit is not thread-safe you should not do this. Android provides several ways for you to update the GUI from a thread.

Here's a short example from the Android Developer page Processes and Threads:

public void onClick(View v) {
    new Thread(new Runnable() {
        public void run() {
            // a potentially  time consuming task
            final Bitmap bitmap =
                    processBitMap("image.png");
            mImageView.post(new Runnable() {
                public void run() {
                    mImageView.setImageBitmap(bitmap);
                }
            });
        }
    }).start();
}

As you can imagine this code will get more and more complicated as you do more stuff. Instead of using these rather raw methods we suggest using AsyncTask.

AsyncTask

With AsyncTask you can perform tasks in the background, update the GUI while working (typically using a progress bar) and finally update the GUI when done. When using AsyncTask you make use of:

To use AsyncTask you subclass AsyncTask. An AsyncTask instance is started using execute(), which in turn invokes doInBackground and onPostExecute methods. Doing something in the background most likely requires someting to work with. In the example below we will download URLs. Instead of simply passing parameters to doInbackground (e. g. URLs) and onPostExecute we do some other steps:

  • subclass AsyncTask using the following parameters:
    • type of parameters - the type of the parameters sent to the task upon execution
    • progress value - the type of the progress units published during the background computation
    • result value - the type of the result of the background computation
  • pass the parameters to doInBackground

Note: the examples on this page are directly copied from the Android Developer page AsyncTask


Extend Async

Imagine you want to download a couple of web pages where you would like to:

  • pass URLs (as parameters) to download
  • update the GUI while downloading. The update is managed using an Integer representing the progress.
  • get result from the work. The result shall be an Long

Then, you would typically subclass AsyncTask like this:

 private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
 ...
 }

Doing the work

Now it is time to implement the method doInBackground. This method is called when the thread is starting.

     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;
     }

Note that the argument is of type URL which is (by necessity) also the first argument when defining the inner class. Also note that the method returns Long which is (by necessity) also the third argument when defining the inner class:

 private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
 ...
 }

When done

And when we're done with the work (that is, when doInBackground returns) we need to implement the method onPostExecute

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


Note that the argument to the method is of type Long which is, of course, the third argument when defining the inner class:

 private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
 ...
 }

Note: we don't need to implement this method. In this case we want to get a return value from the method doInBackground so we implement the method. If you don't have a need to for example updating the GUI you don't need to implement hits method.

Update when doing

And if you want to give the use feedback about the progress when the work is being performed (that is while doInBackground is being executed) you could implement the method onProgressUpdate:

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

In the doInBackground you can invoke the above method by calling:

publishProgress();

Note that the argument to the method is of type Integer which is, of course, the type of the second argument when defining the inner class:

 private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
 ...
 }

Note: we don't need to implement this method. Only implement this method when you need to update the GUI while working

Starting up the work

And to create an instance of the inner class and let it do the work, we simply write:

 new DownloadFilesTask().execute(url1, url2, url3);

Where url1, url2 and url3 are the URL instances we want to pass to the doInBackground method.

Chapter links

Source code

Github repository: GreatPretender

External links

Further reading

Read more about Button and LinearLayout in the Android API:

Android - the practical way

Book TOC | previous chapter | next chapter