Friday, March 11, 2011

Android Thread Constructs(Part 1): The UI Thread

Earlier, I talked on passing data between threads. I would like to continue the same "thread" of discussion and in the next few posts of this multipart article, explore and try to explain about various ways of performing tasks.

A pictorial and diagrammatic representation makes me understand concepts well. Every time I learn something new, I try to make a diagram in my mind. This helps me understand better. So, I'll be providing my own diagrams along the way.

Note : The diagrams I use are to help myself understand the concept and may not be an exact representation of the concept. You may still need to read the related documentation.

Enough said, lets get into the Thread !

The UI Thread:

So, in an Android application, each application is sandboxed and runs in its own process. Unlike traditional languages, the Android application may not have a single entry point. So, the application can be entered through from any of the application components (Activities, Services, Broadcast receivers) described in the Application Fundamentals on the developer blog.

All these application components run on a single Main thread called as the UI thread. I like to imagine this concept as in figure below:

So, as you see all the components will run on the MainThread or the UI thread. All the lifecycle methods (of Activity, Service, Receivers starting with on*) will run on the UI thread.

One of the main task of the UI thread is to manipulate the user interface. Hence, if you have long tasks to perform, you should not be doing those in the main thread. (I'm sure, you must have read this several times). The reason is that if you perform any long or blocking task - the UI thread will be blocked - hence blocking or delaying the UI updates and will lead the user to think that the system is running slow. The Android platform doesn't want this blame on itself, so when it detects that some long task is running on the UI thread for some application, it will declare that the application is "foobar-ed" and throw out the nasty ANR (Application Not Responding) dialog - pissing off the user and provoking him/her to uninstall, and underrate your application ! Deadly and Evil  :O

So, in order to do longer tasks, from any of the application components, you should create threads. However, its worth noting that you should not manipulate the UI from any worker thread. i.e for example if you run a long task on a thread on a button click as follows:


public void onClick(View v) {
  new Thread(new Runnable() {
    public void run() {
      Bitmap b = loadImageFromNetwork();
      mImageView.setImageBitmap(b);
    }
  }).start();
}
Code source : http://developer.android.com/resources/articles/painless-threading.html

Here, the worker thread is trying to update the UI. As the documentation states, this may lead to hard to find and funny (not for you) problems. So, updating the UI is the job of the main thread. The following figure helps me remember that :)


Now, it is evident and advisable that we do long and/or blocking tasks on worker threads and if any results are produced, convey them to the main thread. In my previous article, I talked about passing data around threads. This involves implementing Handlers, making appropriate Looper calls, obtaining the Message Object and passing it around, getting data from it blah blah blah... (Go read the article if you havent')

Android provides certain constructs that offload from us the tasks for creation and administration of threads and let us focus on what we need to do. IntentService, AsyncTask, HandlerThread are among those.

I'm going to discuss IntentService and AsyncTask (with my diagrammatic representations) in the next articles and then try to come up with rough guidelines regarding when to use each of the constructs.

Stay tuned.

15 comments:

  1. Hi there! One question you could please answer, is there one UI thread or main thread for each activty?or is it the same?

    regards,

    ReplyDelete
  2. @Bluemercury there is one UI thread per application. Each of the applications' components (Activities/Services/Broadcast Receivers) get their turn to run on this UI thread - the lifecycle methods for these components run on the UI thread.
    Hope this helps.

    ReplyDelete
  3. hi there Tejas! Thanks for the reply, so if you have two activities A and B both use the same UI thread?Like the same? or when you go from activity to B, a new UI is created? what im asking if its the same UI thread that's shared to all activities or for each activity a new UI thread is created for that activity alone.

    regards,

    ReplyDelete
  4. @Bluemercury, both the activities will use the same UI thread. As I said there will be only one UI thread per application - shared by all the components.

    ReplyDelete
  5. Ok so imagine this scenario, i have a custom header that has a indeterminate progressbar and its used in all activity screens, so if i launch an async task from activity A it will hide and/or show the progressbar according to the background work but while this is happening i go to activity B, whats the best way to tell to the async task that the progressbar it needs to hide after completing the task is now in the activity B and not on the activity A that launched the async task?

    regards,

    ReplyDelete
  6. Have you considered IntentService instead of AsyncTask. That might simplify things. Just a thought.
    But if you want to stick with AsyncTask, here is one way of doing :
    You can explicitly pass an instance of activity to the async task on creation and attach/detach the activity accordingly. You can see the code listed here :
    https://github.com/commonsguy/cw-android/blob/master/Rotation/RotationAsync/src/com/commonsware/android/rotation/async/RotationAsync.java

    Here the activity is attached/detached on rotation events. You can handle this may be in onDestroy and onCreate.

    ReplyDelete
  7. yes i used that example, but i have a doubt, when i go from activity A to B, if the async task was launched from activity A wont the activity in the async still be the A one, even if im currently in B???i actually used that example to deal with the rotations. My current solution and correct me if this is a wrong approach, was to include a reference to the progressbar view in my application class, and refresh it on the onCreate methods and onRestart so that the async task postexecute method can then get the progressview from the application class and hide it or show it. still i need to check how to attach/detach the thread on the onCreate and on onRestart, but that seems a better idea....

    ReplyDelete
  8. Anyway i need to still study the intentservice implementation because i've been advised to consider it too, at the android google group.

    ReplyDelete
  9. I understand what you want to do (I think so), however, I dont' get the approach you have mentioned above. I mean, will the progress bar be a part of all the activities ?
    Anyways, go thru intentservice as well (i have a post on that too)

    ReplyDelete
  10. well every activity has a header right?well they usually have, so i have a progress bar in the custom header(which is used in every activity since i use a main activity where all my activities extend from).For example, i want to hide the progressbar(in the custom header) after the task is finished, even if the activity were currently viewing was not the one which launched the async task(lets say activity A launched the task and B is now visible). So you could say that the tasks, wherever they are created should know which activity is currently being visible so it can hide (in this case) the progress bar. In the end i can make this question: if activity A launched an async task where in the postexecute method i hide the progressgbar and before this happens i switch to activity B will the async task recognises the progressbar from activity A or B ???
    regards,

    ReplyDelete
  11. Also you posted the github advice, but isnt that only for rotation purposes???if i go from activity A to B and if both A and B extend from the same activity class that has the same onCreate method, will the getLastNonConfigurationInstance() work ? what would i do on the onDestroy method???

    regards,

    ReplyDelete
  12. Hey, that was just my suggestion ! I know the example on github is for rotation. I meant you can do something similar - like when onDestroy of A is called, you can detach that activity and when onCreate of B is called you can attach B to the AsyncTask. In this case AsyncTask cannot be an inner class.

    ReplyDelete
  13. hi there Tejas!yes um using a static inner class, so for that implementation i would need a non inner async task class. Can you help me visualize this?

    regards,

    ReplyDelete
  14. the methods onRetainNonConfigurationInstance and
    getLastNonConfigurationInstance are used for rotation but for switching between activities you cant use them can you?

    regards,

    ReplyDelete
  15. This is one of the simple and good post.I like your blog clarity.This is one of the useful Information.Keep it up.
    Android app developers

    ReplyDelete