A question that is asked by many new Android developers is when to use a service and when to use a background thread for some task that threatens to block the UI thread. This question is somewhat misleading because it suggests that the two options are mutually exclusive. Before attempting an answer to the question we first have to know a little about who Android works with threads.
Android’s Main Thread
When an application is started in Android the system will create a single thread for that application. This thread is called the main thread or sometimes also the UI thread. It has to be noted that the UI thread does not only handle UI tasks. That is why I prefer the name main thread, although I will sometimes use the term UI thread as well.
Among other things, the main thread is responsible for starting the application, i.e. for calling the Application.onStart() method. The name UI thread is justified in the sense that performing longer tasks on this thread means blocking the user interface. For this reason, anything that is computationally more intensive or might take longer for other reasons should be carried out in a thread separate from the main thread.
Creating threads in Android is essentially the same as in any other Java application. You can implement the Runnable interface and you can pass it to a Thread to execute. The question that arises is where the thread should be managed.
For many tasks you can simply manage the thread in the Activity. Depending on your requirements, you can start the thread in the Activity.onStart() method and cancel it in the Activity.onStop() method. Alternatively you can use the Activity.onCreate() and Activity.onDestroy() methods for managing the threads.
Sometimes your thread needs to run across your whole application. That means it should stay alive even if the user navigates from one Activity to the next. In this case is is better to manage the thread in an application wide context. One way of doing this is to extend the Application class and override its onCreate() method to start a worker thread. Another alternative is to use singletons. I will go into the details of these two choices in another post.
Android beginners often assume that services run in a separate thread because they are designed to run background tasks. This is not the case! By default a service will be called on the main thread. This confusion often arises because the main thread is referred to as UI thread and services are supposed to run in the background.
If you are doing complex tasks within services then you must create a worker thread within that service. A service is not an alternative to background threads but it provides another scope in which to run your worker threads! You should always create a separate thread within a service if you are doing something more complicated.
The Service class differs from the previous scopes by its life cycle. Implementing a service tells the Android system that the thread should stay alive, even when the user is not interacting with the application. In addition, a Service can be started from another application using an Intent. If neither of these two properties is required by your background task then you should not use a Service but a background thread in another context.
In all of the above cases, worker threads are not managed by the Android system and you should terminate them when they are no longer needed. This means that a thread that is created in Activity.onStart() should be terminated in Activity.onStop(). Otherwise you will be creating new threads every time that the activity starts, resulting in leaking threads. This can be extremely devastating for performance.
The opening question, whether to use a service or a background thread is not an either/or question. Whenever you have a longer task to perform you should delegate it to a worker thread. The question should really be:
“Who should be managing the worker thread?”
The answer depends on the type of task. A thread managed by the activity should terminate when the activity stops or is destroyed. A thread managed inside the Application class or inside another global application-wide object can perform background tasks across multiple activities. Managing a worker thread in a service tell the Android system that it wants to stay alive, even when there is no user interaction with the application.