Comparison of a local, in-process, base class Service✱ to an AsyncTask
:
✱ (This answer does not address exported services, or any service that runs in a process different from that of the client, since the expected use cases differ substantially from those of an AsyncTask
. Also, in the interest of brevity, the nature of certain specialized Service
subclasses (e.g., IntentService
, JobService
) will be ignored here.)
Process Lifetime
A Service
represents, to the OS, "an application's desire to perform a longer-running operation while not interacting with the user" [ref].
While you have a Service
running, Android understands that you don't want your process to be killed. This is also true whenever you have an Activity
onscreen, and it is especially true when you are running a foreground service. (When all your application components go away, Android thinks, "Oh, now is a good time to kill this app, so I can free up resources".)
Also, depending on the last return value from Service.onCreate()
, Android can attempt to "revive" apps/services that were killed due to resource pressure [ref].
AsyncTasks
don't do any of that. It doesn't matter how many background threads you have running, or how hard they are working: Android will not keep your app alive just because your app is using the CPU. It has to have some way of knowing that your app still has work to do; that's why Services
are registered with the OS, and AsyncTasks
aren't.
Multithreading
AsyncTasks
are all about creating a background thread on which to do work, and then presenting the result of that work to the UI thread in a threadsafe manner.
Each new AsyncTask
execution generally results in more concurrency (more threads), subject to the limitations of the AsyncTasks's
thread-pool [ref].
Service
methods, on the other hand, are always invoked on the UI thread [ref]. This applies to onCreate()
, onStartCommand()
, onDestroy()
, onServiceConnected()
, etc. So, in some sense, Services
don't "run" in the background. Once they start up (onCreate()
), they just kinda "sit" there -- until it's time to clean up, execute an onStartCommand()
, etc.
In other words, adding additional Services
does not result in more concurrency. Service methods are not a good place to do large amounts of work, because they run on the UI thread.
Of course, you can extend Service
, add your own methods, and call them from any thread you want. But if you do that, the responsibility for thread safety lies with you -- not the framework.
If you want to add a background thread (or some other sort of worker) to your Service
, you are free to do so. You could start a background thread/AsyncTask
in Service.onCreate()
, for example. But not all use cases require this. For example:
- You may wish to keep a
Service
running so you can continue getting location updates in the "background" (meaning, without necessarily having any Activities
onscreen).
- Or, you may want to keep your app alive just so you can keep an "implicit"
BroadcastReceiver
registered on a long-term basis (after API 26, you can't always do this via the manifest, so you have to register at runtime instead [ref]).
Neither of these use cases require a great deal of CPU activity; they just require that the app not be killed.
As Workers
Services
are not task-oriented. They are not set up to "perform a task" and "deliver a result", like AsyncTasks
are. Services
do not solve any thread-safety problems (notwithstanding the fact that all methods execute on a single thread). AsyncTasks
, on the other hand, handle that complexity for you.
Note that AsyncTask
is slated for deprecation. But that doesn't mean your should replace your AsyncTasks
with Services
! (If you have learned anything from this answer, that much should be clear.)
TL;DR
Services
are mostly there to "exist". They are like an off-screen Activity
, providing a reason for the app to stay alive, while other components take care of doing the "work". AsyncTasks
do "work", but they will not, in and of themselves, keep a process alive.