Given the use case where the user has to perform an online transaction, eg online payment, using the app.
This should be done without blocking the UI, so i was going to use AsyncTask. The problem is with the following scenario:
- the user rotates the phone or gets an incoming call in the middle of the transacion, thus causing the activity to be destryed.
If I understood correctly the asynctask now has a reference to a stale object. So after the transaction is done, there is no way to inform the user about the result. Is it?
Should be use a service instead?
What is a Service?
Most confusion about the Service class actually revolves around what it is not:
A Service is not a separate process. The Service object itself does not imply it is running in its own process; unless otherwise specified, it runs in the same process as the application it is part of.
A Service is not a thread. It is not a means itself to do work off of the main thread (to avoid Application Not Responding errors).
Should you use a service or a thread?
A service is simply a component that can run in the background even when the user is not interacting with your application. Thus, you should create a service only if that is what you need.
If you need to perform work outside your main thread, but only while the user is interacting with your application, then you should probably instead create a new thread and not a service. For example, if you want to play some music, but only while your activity is running, you might create a thread in onCreate(), start running it in onStart(), then stop it in onStop(). Also consider using AsyncTask or HandlerThread, instead of the traditional Thread class. See the Processes and Threading document for more information about threads.
Remember that if you do use a service, it still runs in your application's main thread by default, so you should still create a new thread within the service if it performs intensive or blocking operations.
What causing the activity to be destryed when user rotates the phone?
If the configuration of the device (as defined by the Resources.Configuration class) changes, then anything displaying a user interface will need to update to match that configuration. Because Activity is the primary mechanism for interacting with the user, it includes special support for handling configuration changes.
Unless you specify otherwise, a configuration change (such as a change in screen orientation, language, input devices, etc) will cause your current activity to be destroyed, going through the normal activity lifecycle process of onPause(), onStop(), and onDestroy() as appropriate. If the activity had been in the foreground or visible to the user, once onDestroy() is called in that instance then a new instance of the activity will be created, with whatever savedInstanceState the previous instance had generated from onSaveInstanceState(Bundle).
Possible workaround to solve AsyncTask interruption due to Activity recreation:
In some special cases, you may want to bypass restarting of your activity based on one or more types of configuration changes. This is done with the android:configChanges attribute in its manifest. For any types of configuration changes you say that you handle there, you will receive a call to your current activity's onConfigurationChanged(Configuration) method instead of being restarted. If a configuration change involves any that you do not handle, however, the activity will still be restarted and onConfigurationChanged(Configuration) will not be called.
Related
Question: What is the best practice for reporting progress/complete from long running task to an Activity? And what to do when the progress/complete report happens while the Activity is in the background/orientation changes?
Real life example:
An Activity makes a network call getting data from a server (this could take 10+ sec).
When this network call is finished, the Activity should be notified and the Activity should show that the network call is finished.
This is easy to implement as long as the app stays open. My problem is, what to do if the network call is finished while the app is in the background (activity will miss any callbacks).
I have been looking at the following ways to do this, but I can not decide what to do:
Service that spawns a thread where the network call is executed. The Service is bound to the Activity. On network call finish, Service callbacks to the Activity. If Activity is in background when the Service makes a callback (therefore the Activity misses the callback), should the Activity poll the Service for saved data?
IntentService that broadcasts the data when network call is finished (what to do if Activity misses this broadcast because it is in background?)
AsyncTask, but this is bad when Activity is in background etc.
How should I approach this problem?
I've solved this problem using HeadlessFragments as its called. This blog post explains in detail how to implement it and the concerns you mentioned are handled by it.
EDIT:
For the questions in the comment:
To your specific question, about callbacks being lost when Activity is in the background, the answer is no. Being in "background" means that Activity is still alive. From the link I posted, the callback, which is the Activity itself, is removed when its detached from the Activity i.e when the Activity is destroyed. So, if your Activity is in the background and not destroyed, it'll still get the callback and do whatever you do in that callback. Although Android can kill Activities that are paused, in which case, your Activity will be destroyed and you won't get the callback. In such case, you can either save the data you get from server in a persistent storage, like SQLite, and prevent making another network call or make the network call when the Activity is created which will ensure that whenever the Activity is created, you'll have data to display (given of course, the call goes through).
The use of Fragment was specifically to handle the configuration change you mentioned in your question. The running task is still being done by the AsyncTask and not by the Fragment. The Fragment only holds a reference to the object. So, I'd argue about it not being a "best practise".
Until today, I used services by starting them, using startService(), because I needed to do work also when all the activities was destroyed.
Now, I have a task that needs to be done in the background as long as my activity is alive.
Is there a reason for me to bind the activity to a service instead of doing the work in a separate thread?
It leads me to the question in the title:
Why would anyone want to bind service (without creating it before), instead of using a Thread?
Services and Thread have two different goals. As you mentioned, Service can live longer after the activity was destroyed. Depending on the Service you subclassed it runs or not on the UI Thread. They have their own life cycle and are a construct of the Android SDK. Threads are unit of executions whose flow is parallel to the ui thread. It allows you to execute long term tasks leaving the ui responsive. The Thread lives as long as its run's method. You should make sure that its execution is completed before your Activity or Fragment calls its onDestroy method.
Why would anyone want to bind service instead of using a Thread?
The answer is it depends. If you need to run your task also when you Activity is destroyed, then a Service is the natural choice. Otherwise you can use a simple thread. Think, for instance, about downloading a huge file from the net. You want to run this task also when the activity is not at screen but, at the same time, you want to show to the user the current progress (in percentage maybe) of the download. If you are using a Service to run this task, this one holds also those information. To update your UI, which is part of the Activity, you could either Broadcast those information, or retrive the Service object, the one you get when your service is bound, to retrieve this information (providing a delegate). Since you get an instance of your service, you can use it to send different kind of commands (e.g. stop the download).
Is there a reason for me to bind the activity to a service
instead of doing the work in a separate thread?
If your thread lives in a non static member variable of the activity and the activity is recreated after screen rotation your thread is lost or has to be recreated.
With a service you can reconnect to the service after rotation.
Instead of using a naked thread or a service i prefer to use a LoaderManager with an AsyncTask to do the background task while the activity is visible. The LoaderManager is also capable of reconnecting to the running AsyncTask
I avoid using static member variable for thread/AsyncTask because of memory leaking issues.
I am finishing my current activity using finish(). This is calling onPause automatically. I want to finish activity without onPause being called. My activity is running a song service so i want song to stop when app is in background but dont want it to stop when user goes from one activity into another in my app. I cant do stopService and startService in between activities because then there is a momentary lag in between the sounds.
A Service is an application component that can perform long-running operations in the background and does not provide a user interface
google docs
The background Service is agnostic of which Activity is running or any discontinuity between them.
The two types, "bound" and "started" are supposed to have different persistence characteristics but in practice (not stress testing) I find the bound Service does not clobbered for lack of system memory and is much easier to implement (despite tutorials claiming otherwise). It uses some IPC abstraction that appears as though it is being directly invoked from the Activity. The same can't be said of the "started" variety (unless it is also bound) which is IMO a closer approximation to the traditional service I would associate with web-servers (or anything that is already going to be experiencing not insignificant delays- such as due to network transmission).
(Lecture over) I see you are calling finish(). You need some way to shut down the Service from your Activity. Just make sure to branch aways from doing so when not intended. Code would be helpful but I can assure you this is how media players work.
I am developing an Android data entry app that saves the entered data to a file. A Service (let's call it FileIOService) is launched using the filename, and loads and saves data that is passed to it from each Activity that the user accesses.
I am trying to make the whole app as robust as possible, and at the moment I feel I need to pay particular attention to the interaction between each Activity and the Service. Here are the issues I can see:
If the Service is killed by the system, it needs to restart and open the file that it had open: I can handle this by using START_REDELIVER_INTENT.
If an Activity is destroyed, for instance by an orientation change, it needs to reconnect to the Service.
The thing is, once the Activity launches the Service, there's a while before the Service finishes opening the file and becomes ready for I/O requests. To address this, in my Activity, I have both:
an inner class subclassing ServiceConnection, with its onServiceConnected() method completed
a private reference to an anonymous inner subclass of BroadcastReceiver, with its handleMessage() method completed. This gets called when the Service sends out a broadcast to indicate it's finished opening its file.
Both of these methods then call a setUpActivity() method that pulls data from the Service. This is where it starts to get ugly. Because onServiceConnected() may run before the file is ready for I/O, and handleMessage() might be called while the Service is not bound to the Activity, I have to make both handleMessage() and onServiceConnected() set boolean flags that can later be checked in setUpActivity(), like this:
if ((fileLoaded && serviceConnected))
{
//access the file data
}
As I said, this feels ugly and awkward, and relies on setting extra boolean variables.
There's another problem - if my Activity launches an external Activity, like the Camera app, upon returning to my app the Service and Activity may both have been destroyed (especially with an orientation change) and the app crashes.
My feeling is that I may be missing some overall pattern that would define how each Activity should relate to the Service, and vice versa, while remaining robust and able to cope with unexpected terminations/restarts.
Let's ignore the fact that I am skeptical that this is a valid use case for a service (a service whose existence is simply to read and write files?).
If the Service is killed by the system, it needs to restart and open the file that it had open: I can handle this by using START_REDELIVER_INTENT.
The service is not "killed by the system". The process is killed by the system. This will eradicate your activities as well as your service.
The one possible exception to this is if the user manually stops the service (and only the service) from Settings, in which case I have no clue what the expected behavior would be. This should be fairly uncommon nowadays, particularly for an app that the user had just been using. Users will be more inclined to use a task manager, such as swiping your app off the recent-tasks list, which will get rid of the entire process, not just the service.
If an Activity is destroyed, for instance by an orientation change, it needs to reconnect to the Service.
Not necessarily:
Bind using the Application context (getApplicationContext()) instead of from the Activity directly
Use a retained fragment to maintain the binding across the configuration change
My feeling is that I may be missing some overall pattern that would define how each Activity should relate to the Service, and vice versa, while remaining robust and able to cope with unexpected terminations/restarts.
This is one of the many reasons why I try to avoid the binding pattern altogether. Use a service for processing commands, sent via startService(), with results (if any) delivered by LocalBroadcastManager, or Otto, or greenrobot's EventBus, or a "real" broadcast Intent, or maybe a Messenger. Particularly when the service is an IntentService, the service nicely cleans up after itself when there is no more work to be done.
Is there any difference in running background threads from an Activity and from a Service that is started by the Activity? Added: The background threads do not interact with the UI.
I currently have some background threads that are launched from the Activity. Most are via AsyncTask and one is through my own ExecutorService. I would like to know if there is a significant benefit to refactoring the code to move these to a Service or IntentService.
You seem to be confused about the definition of Activities and Services. To make it clear:
Activities are things that run according to the Activity lifecycle state machine. The code in the respective handlers interacts with an event loop attached to a UI.
Services are things that run according to the Service lifecycle state machine. The code in the respective lifecycle handlers performs operations to handle things like Intents, etc..., but does not interact with the user via a UI.
Both of these, however, run on the "main thread" of the application. By itself, an Activity or a Service (or Broadcast Receiver, Content provider, etc...) is not a thread. Look at the documentation, and you will see that the Activity and Service classes do not, in fact, form a thread. Instead, they are hooks that will run inside the Android framework, and the framework will at the appropriate time call them on the "main" thread of the app.
You can create separate threads for the app, or use an AsyncTask to do work and publish it to the UI thread easily (something not so easily achieved with a Service).
Threads that are bound to Activities have the same lifecycle. So if you restart/kill the Activity, the thread will also be restarted/killed. This is a problem if you don't manage the lifecycle of an Activity. A service is good in this case. You can have the activity destroyed and still a worker thread running in the background (in the service). But be advised that, if the Android system need resources (memory for example) it will kill the services first (and then restart them according to their Sticky flag). In my opinion, there are no actual benefit in changing threads from the Activity to a Service, since you control the workflow of your activity. If the threads are heavy (and brake the UI for moments) consider putting them in a service on a separate process (in AndroidManifest put the process name of the service).
In Android documentation:
Caution: Another problem you might encounter when using a worker
thread is unexpected restarts in your activity due to a runtime
configuration change (such as when the user changes the screen
orientation), which may destroy your worker thread. To see how you can
persist your task during one of these restarts and how to properly
cancel the task when the activity is destroyed, see the source code
for the Shelves sample application.