In this series of posts we have seen the following thread constructs:
1. Basic threads and communication between them [see
article]
2. Understanding the Main thread or the UI thread [see
article]
3. IntentService [see
article]
4. AsyncTask [see
article]
NOTE: These are Android specific constructs. Android also
includes the java.util.concurrent package which can be leveraged for
concurrent tasks. That is out of the scope of my discussion.]
So, when to use what ? What is the exact purpose of each ? What are the
drawbacks of using one over the other ? Which one is easier to program ?
I came across all these questions when trying to understand each of
these. In due course of time, I have come up with some guidelines which I
discuss in this post.
NOTE: Any of the recommendations made in this post and the table
below are not comprehensive and final. There may be better and alternate
ways of doing things. I would love to know any different views and get
an insight into a different thought process. The views expressed in this
post are my personal views.
Service
Before proceeding further, let me touch on the Service class.
Traditionally speaking, the notion of service reminds us of task running
in the background while we can work and interact with the UI. This
causes confusion for newbies. Because in Android, even if the Service
runs in the background, it runs on the Main Thread of the application.
So, if at the same time if you have an activity displayed, the running
service will take the main thread and the activity will seem slow. It is
important to note that a Service is just a way of telling Android that
something needs to run without a user interface in the background while
the user may not interacting with your application. So, if you expect
the user to be interacting with the application while the service is
running and you have a long task to perform in a service, you need to
create a worker thread in the Service to carry out the task.
So, even if Service is not a threading construct, its a way of executing
a task at hand. Hence I have included it in the comparison.
The table below tries to summarize various aspects of four
task execution mechanisms : Service, Thread, IntentService, AsyncTask.
Most
of the points in the table are self-explanatory. However, some points
that need an explanation are numbered and explained below the
table. Also, this table is just to summarize about the concepts
discussed in the previous posts. So, if anything is still unclear, I
recommend to go through each individual posts in this series.
| Service | Thread | IntentService | AsyncTask |
When to use ? | Task with no UI, but shouldn't be too long. Use threads within service for long tasks. | - Long task in general.
- For tasks in parallel use Multiple threads (traditional mechanisms) | - Long task usually with no communication to main thread.
(Update)- If communication is required, can use main thread handler or broadcast intents[3]
- When callbacks are needed (Intent triggered tasks). | - Long task having to communicate with main thread.
- For tasks in parallel use multiple instances OR Executor [1] |
Trigger | Call to method
onStartService() | Thread start() method | Intent | Call to method execute() |
Triggered From (thread) | Any thread | Any Thread | Main Thread (Intent is received on main thread and then worker thread is spawed) | Main Thread |
Runs On (thread) | Main Thread | Its own thread | Separate worker thread | Worker thread. However, Main thread methods may be invoked in between to publish progress. |
Limitations /
Drawbacks | May block main thread | - Manual thread management
- Code may become difficult to read | - Cannot run tasks in parallel.
- Multiple intents are queued on the same worker thread. | - one instance can only be executed once (hence cannot run in a loop) [2]
- Must be created and executed from the Main thread |
[1]
API Level 11 (Android 3.0) introduces the executeOnExecutor() method,
that runs multiple tasks on a thread pool managed by AsyncTask. Below
API Level 11, we need to create multiple instances of AsyncTask and call
execute() on them in order to start parallel execution of multiple
tasks.
[2]
Once you create an object of an AsyncTask and call execute, you cannot
call execute on that object again. Hence, trying to run an AsyncTask
inside a loop will require you to each time create a new object in the
loop before calling the execute on it.
To be very precise, you cannot do something like :
TestAsyncTask myATask = new TestAsyncTask();
for (int i = 0; i < count; i++) {
myATask.execute("one", "two", "three", "four");
}
But you can do :
for (int i = 0; i < count; i++) {
TestAsyncTask myATask = new TestAsyncTask();
myATask.execute("one", "two", "three", "four");
}
[3] Thanks to comment posted by () : "there's
nothing stopping an IntentService from communicating back to
activities. A broadcast Intent is good for that, particularly with
setPackage() to keep it constrained to your app (available on Android
2.1, IIRC). An ordered broadcast can be particularly useful, as you can
rig it up such that if none of your activities are on-screen, that some
manifest-registered BroadcastReceiver picks up the broadcast and raises a
Notification."
Conclusion:
With a pretty understanding of the AsyncTask and the IntentService
classes provided by Android, it would be a good idea to leverage these
for most of the tasks as against trying to manage threads manually or
implement your class as a Service unless there is really a need to do
so.
Tricky Things:
There are some tricky scenarios that need some special handling. After
all, we are dealing with a mobile environment and things are pretty
unpredictable. For instance, the user opens your activity in which you
start an AsyncTask, but before completion of the task, the user decides
to exit the application (say by pressing the back button). Or your
activity may be terminated (read kicked off) due to say an incoming
call, when you are running a long task in the background. In such cases,
where your application is not shutdown, but any foreground tasks have
been closed or changed, all the background tasks need to know of this
and try to exit gracefully.
阅读(550) | 评论(0) | 转发(0) |